solunar 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ 01 055 044 052 039 033 016 010 002 000 001 004 005
2
+ 02 045 035 042 028 023 008 004 000 002 003 008 010
3
+ 03 036 026 033 019 014 003 001 001 006 007 014 016
4
+ 04 027 017 023 011 006 000 000 004 011 012 021 024
5
+ 05 019 010 015 004 002 001 002 009 017 019 030 033
6
+ 06 012 005 008 001 000 004 006 015 025 027 039 043
7
+ 07 006 001 003 000 002 009 013 023 034 036 049 054
8
+ 08 002 000 000 003 006 017 020 031 043 046 060 065
9
+ 09 000 002 001 008 012 025 029 041 053 056 070 075
10
+ 10 001 006 004 016 021 035 038 050 062 066 080 085
11
+ 11 004 013 010 025 030 044 047 059 072 075 088 092
12
+ 12 009 022 019 035 040 054 057 069 081 084 095 097
13
+ 13 016 033 029 046 051 063 066 077 088 092 099 100
14
+ 14 026 044 040 056 060 072 075 085 094 097 100 099
15
+ 15 036 055 051 066 070 080 083 092 099 100 098 096
16
+ 16 048 066 061 075 078 087 089 097 100 099 093 090
17
+ 17 059 076 071 083 085 093 095 099 099 096 086 082
18
+ 18 070 084 080 090 091 097 098 100 095 090 077 073
19
+ 19 079 091 087 095 096 099 100 098 088 082 067 063
20
+ 20 088 096 093 098 099 100 099 093 079 072 056 053
21
+ 21 094 099 097 100 100 098 096 086 069 062 046 044
22
+ 22 098 100 099 100 099 094 091 077 058 051 036 034
23
+ 23 100 099 100 098 097 089 084 066 046 040 027 026
24
+ 24 099 096 099 094 092 081 074 055 036 030 019 018
25
+ 25 097 092 095 089 086 072 064 043 026 021 012 011
26
+ 26 093 086 091 082 078 061 053 032 017 014 007 006
27
+ 27 087 079 085 074 069 050 041 022 010 008 003 002
28
+ 28 080 071 077 065 058 039 030 014 005 004 001 000
29
+ 29 072 062 069 054 047 028 020 007 002 001 000 000
30
+ 30 063 *** 059 044 036 018 012 003 000 000 002 002
31
+ 31 054 *** 049 *** 026 *** 006 000 *** 001 *** 006
@@ -0,0 +1,31 @@
1
+ 01 012 024 012 028 035 052 057 070 080 083 092 094
2
+ 02 019 034 021 039 046 063 067 078 087 090 097 099
3
+ 03 028 045 031 050 057 072 075 085 093 095 100 100
4
+ 04 038 057 042 061 067 080 083 091 097 099 099 098
5
+ 05 049 068 053 071 076 087 090 096 100 100 096 093
6
+ 06 061 078 064 080 084 093 095 099 100 099 091 086
7
+ 07 071 087 075 088 091 097 098 100 097 095 083 077
8
+ 08 081 094 084 094 096 099 100 099 093 088 073 067
9
+ 09 090 098 091 098 099 100 100 096 086 080 062 056
10
+ 10 096 100 096 100 100 099 098 091 077 070 051 046
11
+ 11 099 099 099 100 099 096 094 084 067 059 040 035
12
+ 12 100 097 100 098 097 091 088 075 056 047 030 026
13
+ 13 098 092 099 094 093 085 081 065 045 036 021 018
14
+ 14 093 085 095 089 087 077 072 054 033 026 013 011
15
+ 15 087 078 090 082 080 068 062 042 023 017 007 006
16
+ 16 079 069 084 075 072 058 051 031 014 010 003 002
17
+ 17 071 060 076 066 063 047 040 021 007 005 001 000
18
+ 18 061 051 068 057 053 036 029 012 003 001 000 000
19
+ 19 052 041 059 047 043 026 019 005 000 000 002 002
20
+ 20 042 032 049 037 032 016 010 001 000 001 005 005
21
+ 21 033 024 040 027 022 009 004 000 003 004 010 010
22
+ 22 025 016 030 018 014 003 001 001 007 009 016 017
23
+ 23 017 009 022 010 007 000 000 005 013 015 023 025
24
+ 24 010 004 014 005 002 001 003 010 020 022 031 034
25
+ 25 005 001 007 001 000 004 007 018 028 030 041 044
26
+ 26 002 000 003 000 002 010 014 026 037 039 051 054
27
+ 27 000 002 000 003 006 018 022 035 047 048 061 064
28
+ 28 001 006 001 008 013 027 032 044 056 058 071 075
29
+ 29 003 *** 004 015 021 037 041 054 065 068 080 084
30
+ 30 008 *** 010 025 031 047 051 063 074 077 088 092
31
+ 31 015 *** 018 *** 042 *** 061 072 *** 085 *** 097
@@ -0,0 +1,32 @@
1
+ 01 100 098 100 098 097 091 089 079 065 058 038 031
2
+ 02 099 093 099 094 093 085 083 071 054 046 028 022
3
+ 03 096 087 096 089 087 078 075 061 043 035 018 013
4
+ 04 090 078 091 082 080 069 066 050 032 024 010 007
5
+ 05 082 069 084 073 072 060 056 039 022 015 005 003
6
+ 06 072 059 076 065 063 050 046 029 013 008 001 000
7
+ 07 062 049 066 055 053 040 035 019 006 003 000 000
8
+ 08 052 040 057 046 044 031 025 010 002 000 001 002
9
+ 09 042 031 047 037 034 021 016 004 000 001 005 006
10
+ 10 032 022 038 028 025 013 008 001 002 003 010 011
11
+ 11 024 015 029 019 017 006 003 000 006 008 017 018
12
+ 12 016 009 021 012 010 002 000 003 012 015 024 025
13
+ 13 010 004 014 006 004 000 001 008 020 023 033 034
14
+ 14 005 001 008 002 001 001 004 015 029 031 042 043
15
+ 15 002 000 003 000 000 006 010 024 038 041 051 053
16
+ 16 000 001 001 001 002 012 018 034 048 050 061 062
17
+ 17 000 004 000 004 007 021 028 044 058 060 070 072
18
+ 18 002 008 002 009 014 031 039 054 067 069 078 081
19
+ 19 006 015 006 017 024 042 049 064 075 077 086 088
20
+ 20 012 023 012 026 034 053 060 073 083 085 092 095
21
+ 21 019 033 020 037 046 064 069 081 089 091 097 099
22
+ 22 028 044 029 048 057 074 078 088 095 096 100 100
23
+ 23 038 055 040 060 067 082 086 093 098 099 100 099
24
+ 24 048 066 051 070 077 089 092 097 100 100 097 094
25
+ 25 059 076 063 080 085 094 096 099 099 099 092 087
26
+ 26 070 086 073 088 092 098 099 100 097 095 084 079
27
+ 27 080 093 083 094 096 100 100 098 093 089 075 068
28
+ 28 089 098 091 098 099 100 099 095 086 081 064 057
29
+ 29 095 *** 096 100 100 098 097 090 078 072 053 046
30
+ 30 099 *** 099 099 099 094 093 083 068 061 042 036
31
+ 31 100 *** 100 *** 096 *** 087 074 *** 049 *** 026
32
+
@@ -0,0 +1,31 @@
1
+ 01 017 009 020 012 010 003 002 001 008 013 025 027
2
+ 02 010 004 013 007 005 001 000 004 016 021 034 036
3
+ 03 005 001 007 003 002 000 001 010 025 030 044 045
4
+ 04 002 000 003 001 000 002 005 019 035 041 053 054
5
+ 05 000 001 001 000 001 007 012 028 046 051 063 064
6
+ 06 000 003 000 002 004 014 021 039 057 060 071 073
7
+ 07 003 007 001 006 009 023 031 050 066 070 079 081
8
+ 08 006 013 004 012 016 033 042 061 075 078 087 088
9
+ 09 012 020 009 019 025 044 053 071 083 085 092 093
10
+ 10 019 029 015 028 035 056 064 080 090 091 097 098
11
+ 11 026 038 023 039 047 067 074 087 095 096 099 100
12
+ 12 035 048 033 050 058 077 083 093 098 099 100 100
13
+ 13 045 059 043 061 069 086 090 097 100 100 098 097
14
+ 14 055 069 054 072 079 092 095 099 100 099 095 093
15
+ 15 065 079 065 082 088 097 099 100 098 097 090 086
16
+ 16 075 088 075 090 094 100 100 099 094 092 082 077
17
+ 17 084 095 084 096 098 100 099 095 089 086 073 066
18
+ 18 091 099 092 099 100 098 097 091 082 078 063 055
19
+ 19 097 100 097 100 099 094 093 085 074 069 052 044
20
+ 20 100 098 100 098 096 089 087 077 064 059 040 033
21
+ 21 100 093 099 093 091 082 080 068 054 048 029 023
22
+ 22 096 086 096 087 084 074 072 059 043 037 019 014
23
+ 23 091 078 090 079 077 066 063 049 033 026 011 007
24
+ 24 082 068 083 071 068 056 053 038 022 016 005 003
25
+ 25 073 058 074 061 059 047 043 028 013 008 001 000
26
+ 26 062 047 064 052 050 037 033 019 006 003 000 000
27
+ 27 052 038 054 042 040 028 024 011 002 000 002 003
28
+ 28 041 028 045 033 031 019 015 004 000 001 005 007
29
+ 29 031 *** 035 025 022 012 008 001 002 004 011 013
30
+ 30 022 *** 026 017 015 006 003 000 006 009 018 020
31
+ 31 015 *** 019 *** 008 *** 000 003 *** 016 *** 028
@@ -0,0 +1,31 @@
1
+ 01 037 047 039 054 060 079 086 096 100 100 099 098
2
+ 02 046 057 049 064 071 087 093 099 100 099 096 095
3
+ 03 055 066 059 074 081 094 097 100 098 097 091 089
4
+ 04 065 076 070 084 089 098 100 099 094 093 085 082
5
+ 05 074 084 079 092 096 100 100 095 089 087 078 074
6
+ 06 082 091 087 097 099 099 097 091 082 080 069 064
7
+ 07 089 097 094 100 100 095 093 084 074 072 059 053
8
+ 08 095 099 098 099 098 090 087 077 066 063 048 042
9
+ 09 099 100 100 096 093 082 079 068 056 053 037 031
10
+ 10 100 097 098 090 086 074 071 059 047 043 027 021
11
+ 11 099 091 094 082 077 065 062 050 037 032 017 012
12
+ 12 095 083 087 073 068 055 052 040 027 022 009 005
13
+ 13 089 074 078 063 058 046 043 031 018 014 003 001
14
+ 14 080 063 068 052 049 036 034 022 010 007 000 000
15
+ 15 070 052 057 042 039 027 025 014 004 002 000 002
16
+ 16 059 041 046 033 030 019 017 007 001 000 003 006
17
+ 17 048 031 036 024 022 012 010 003 000 001 009 012
18
+ 18 037 022 027 016 014 007 005 000 003 006 017 020
19
+ 19 026 014 019 010 008 002 001 001 008 013 026 029
20
+ 20 018 008 012 005 004 000 000 004 016 021 036 038
21
+ 21 010 003 006 002 001 000 001 010 025 031 046 048
22
+ 22 005 001 003 000 000 002 005 018 036 042 056 057
23
+ 23 001 000 001 001 001 007 012 028 047 052 065 067
24
+ 24 000 001 000 003 004 014 020 039 057 062 074 075
25
+ 25 001 004 002 007 009 022 030 050 068 072 082 083
26
+ 26 003 009 005 012 016 032 041 061 077 080 088 089
27
+ 27 008 015 010 020 025 043 053 071 085 087 094 095
28
+ 28 014 022 016 028 035 055 064 081 091 093 097 098
29
+ 29 021 030 024 038 046 066 074 088 096 097 100 100
30
+ 30 029 *** 033 049 057 077 083 094 099 099 100 100
31
+ 31 038 *** 043 *** 068 *** 091 098 *** 100 *** 097
@@ -0,0 +1,31 @@
1
+ 01 093 082 092 079 072 056 051 039 028 025 013 010
2
+ 02 086 072 085 068 062 046 042 030 019 017 007 004
3
+ 03 078 061 075 058 051 036 032 022 012 009 002 001
4
+ 04 068 050 065 046 040 027 024 014 006 004 000 000
5
+ 05 057 039 054 036 031 019 016 008 002 001 001 003
6
+ 06 046 028 042 026 022 012 010 004 000 000 005 009
7
+ 07 035 019 032 018 014 006 005 001 001 002 012 017
8
+ 08 024 011 022 011 008 003 002 000 004 007 021 026
9
+ 09 015 005 014 005 004 000 000 002 009 015 031 036
10
+ 10 008 001 008 002 001 000 001 006 017 024 042 047
11
+ 11 003 000 003 000 000 002 003 012 027 035 052 057
12
+ 12 000 001 001 000 001 005 008 020 038 046 063 067
13
+ 13 000 004 000 003 003 010 014 029 049 057 073 076
14
+ 14 003 009 002 006 008 017 022 040 060 067 081 083
15
+ 15 008 016 005 012 014 025 032 051 071 077 088 090
16
+ 16 014 023 010 018 021 035 043 063 080 085 094 095
17
+ 17 022 031 017 026 030 046 054 073 088 092 098 098
18
+ 18 030 040 024 035 039 057 065 083 094 096 100 100
19
+ 19 040 050 033 045 050 068 076 091 098 099 100 100
20
+ 20 049 059 042 055 060 078 085 096 100 100 098 098
21
+ 21 058 069 051 065 071 087 092 099 099 099 095 094
22
+ 22 067 077 061 075 081 094 097 100 097 096 090 089
23
+ 23 076 085 071 084 089 098 100 098 092 091 084 082
24
+ 24 084 092 080 092 095 100 099 094 087 085 076 074
25
+ 25 090 097 088 097 099 099 096 089 080 078 068 064
26
+ 26 095 099 094 100 100 094 091 082 071 070 058 054
27
+ 27 099 100 098 099 098 088 084 073 063 061 048 043
28
+ 28 100 097 100 096 092 080 076 065 053 051 037 032
29
+ 29 099 *** 099 090 085 071 067 055 044 041 027 022
30
+ 30 095 *** 094 082 076 061 058 046 034 031 018 013
31
+ 31 089 *** 088 *** 066 *** 048 037 *** 022 *** 006
@@ -0,0 +1,31 @@
1
+ 01 002 001 001 000 001 005 006 015 029 036 056 063
2
+ 02 000 003 000 002 003 010 012 023 039 047 067 073
3
+ 03 002 008 001 006 008 016 019 032 050 059 077 082
4
+ 04 006 015 005 012 014 023 027 042 061 070 085 089
5
+ 05 012 024 010 019 021 032 036 053 072 080 092 094
6
+ 06 021 033 017 027 029 041 047 064 082 088 097 098
7
+ 07 030 042 025 036 038 051 057 075 090 094 099 100
8
+ 08 040 052 034 045 048 062 068 084 096 098 100 100
9
+ 09 050 061 044 055 057 072 078 092 099 100 098 098
10
+ 10 060 070 053 064 067 081 087 097 100 099 095 094
11
+ 11 069 078 062 073 077 089 094 100 098 096 090 089
12
+ 12 077 085 071 082 085 095 098 099 093 091 083 082
13
+ 13 085 091 079 089 092 099 100 096 087 085 075 074
14
+ 14 091 096 087 095 097 100 098 090 079 077 067 066
15
+ 15 095 099 093 099 100 097 094 083 070 068 058 056
16
+ 16 098 100 097 100 100 092 087 074 061 059 048 046
17
+ 17 100 099 099 099 096 085 079 064 052 050 039 036
18
+ 18 099 095 100 095 090 075 069 054 042 040 029 027
19
+ 19 097 090 097 088 082 065 059 045 033 031 020 018
20
+ 20 093 083 093 080 072 054 049 035 024 023 013 010
21
+ 21 086 074 086 070 062 044 039 027 017 015 006 004
22
+ 22 079 063 077 059 050 034 029 019 010 008 002 001
23
+ 23 069 052 067 047 040 024 021 012 005 003 000 000
24
+ 24 059 041 056 036 029 017 014 007 002 001 001 003
25
+ 25 048 030 044 026 020 010 008 003 000 000 005 008
26
+ 26 037 020 033 017 013 005 004 001 001 002 011 016
27
+ 27 026 012 023 010 007 002 001 000 004 007 019 025
28
+ 28 017 005 014 005 003 000 000 002 009 014 030 036
29
+ 29 009 *** 007 001 000 000 001 006 016 023 040 047
30
+ 30 003 *** 003 000 000 003 004 012 025 033 052 058
31
+ 31 001 *** 000 *** 002 *** 009 019 *** 044 *** 068
@@ -0,0 +1,31 @@
1
+ 01 077 086 073 082 084 093 096 100 096 093 083 081
2
+ 02 084 092 080 089 091 097 099 098 090 086 074 073
3
+ 03 091 096 087 094 096 100 100 094 082 077 065 064
4
+ 04 096 099 093 098 099 099 097 087 072 068 056 055
5
+ 05 099 100 097 100 100 096 092 078 062 058 046 045
6
+ 06 100 099 099 100 099 091 085 068 052 048 037 036
7
+ 07 099 096 100 097 095 083 075 057 042 039 028 027
8
+ 08 097 092 099 093 089 073 065 047 032 030 020 019
9
+ 09 093 086 095 086 081 062 054 037 024 022 013 012
10
+ 10 088 078 090 078 071 051 043 027 016 014 007 006
11
+ 11 081 070 083 068 060 040 032 019 010 008 003 002
12
+ 12 073 060 075 057 048 029 023 012 005 004 000 000
13
+ 13 064 049 065 046 037 020 015 006 002 001 000 001
14
+ 14 054 038 054 035 026 012 009 003 000 000 002 004
15
+ 15 043 028 043 024 017 006 004 001 000 001 006 010
16
+ 16 033 018 032 015 010 002 001 000 003 004 013 018
17
+ 17 023 010 021 008 004 000 000 002 007 009 021 028
18
+ 18 014 004 012 003 001 000 001 005 012 016 031 039
19
+ 19 007 001 006 000 000 003 004 010 020 025 042 050
20
+ 20 002 000 001 000 001 006 008 016 029 035 054 061
21
+ 21 000 003 000 003 005 012 014 024 039 046 065 072
22
+ 22 001 009 001 008 010 019 021 033 049 057 075 081
23
+ 23 006 016 005 014 016 026 029 043 061 068 084 089
24
+ 24 012 025 011 022 024 035 039 054 071 078 092 094
25
+ 25 021 034 019 030 033 045 048 064 081 087 097 098
26
+ 26 031 044 028 039 042 054 059 075 090 094 099 100
27
+ 27 041 054 037 049 051 064 069 084 096 098 100 099
28
+ 28 051 064 047 058 061 074 078 092 099 100 098 097
29
+ 29 061 *** 056 067 070 082 087 097 100 099 094 093
30
+ 30 071 *** 066 076 079 090 094 100 097 095 088 087
31
+ 31 079 *** 074 *** 087 *** 098 099 *** 090 *** 080
@@ -0,0 +1,31 @@
1
+ 01 072 062 069 054 047 027 020 008 002 001 000 000
2
+ 02 063 052 059 043 036 018 012 003 000 000 001 002
3
+ 03 054 042 049 032 025 010 006 001 000 001 005 007
4
+ 04 044 032 038 022 016 004 002 000 003 003 010 013
5
+ 05 035 023 028 013 008 001 000 002 006 008 017 020
6
+ 06 026 014 018 006 003 000 001 005 012 014 025 030
7
+ 07 017 007 010 002 000 002 004 010 018 021 034 040
8
+ 08 010 002 004 000 001 006 008 016 026 030 045 051
9
+ 09 004 000 001 001 004 012 014 024 035 039 056 063
10
+ 10 001 001 000 006 009 019 022 032 045 050 067 073
11
+ 11 000 005 003 012 016 027 030 042 055 060 077 083
12
+ 12 002 011 008 020 024 036 039 051 065 071 086 091
13
+ 13 007 020 016 030 033 046 048 061 075 081 093 096
14
+ 14 015 030 025 040 043 055 058 071 084 089 098 099
15
+ 15 024 041 035 050 053 064 067 080 092 096 100 100
16
+ 16 034 051 046 059 062 073 076 088 097 099 099 097
17
+ 17 046 062 056 069 071 081 084 094 100 100 095 093
18
+ 18 057 072 066 077 079 088 091 098 099 097 089 087
19
+ 19 067 080 075 084 086 094 096 100 096 092 081 079
20
+ 20 077 087 083 091 092 098 099 099 090 085 072 070
21
+ 21 085 093 089 095 097 100 100 094 081 076 063 061
22
+ 22 091 097 094 099 099 099 098 087 072 066 053 052
23
+ 23 096 099 098 100 100 096 093 079 061 056 044 042
24
+ 24 099 100 100 099 098 091 085 068 050 046 034 033
25
+ 25 100 099 100 097 095 083 076 057 040 036 026 025
26
+ 26 099 096 098 092 089 074 066 046 030 027 018 017
27
+ 27 096 091 095 086 081 063 054 036 022 019 011 010
28
+ 28 092 085 089 078 072 052 043 026 014 012 006 005
29
+ 29 086 077 082 069 061 041 032 017 008 007 002 002
30
+ 30 079 *** 074 058 050 030 023 010 004 003 000 000
31
+ 31 071 *** 065 *** 038 *** 014 005 *** 001 *** 001
@@ -0,0 +1,31 @@
1
+ 01 004 013 004 016 021 036 040 052 064 067 081 085
2
+ 02 009 022 010 025 031 046 050 062 073 077 089 093
3
+ 03 017 032 019 036 042 056 059 071 082 085 095 098
4
+ 04 026 043 029 046 052 065 068 079 089 092 099 100
5
+ 05 036 055 040 057 062 074 077 086 095 097 100 099
6
+ 06 047 066 051 067 071 082 084 093 099 100 098 095
7
+ 07 059 076 062 076 080 089 090 097 100 099 093 089
8
+ 08 070 084 072 084 087 094 095 100 099 096 085 081
9
+ 09 079 091 081 091 092 098 099 100 095 090 076 071
10
+ 10 088 096 088 095 097 100 100 098 088 082 066 061
11
+ 11 094 099 094 099 099 100 099 093 079 072 055 051
12
+ 12 098 100 098 100 100 098 096 086 069 061 045 041
13
+ 13 100 099 100 099 099 094 091 077 058 050 035 032
14
+ 14 099 095 100 097 096 088 084 067 047 039 026 024
15
+ 15 096 091 098 093 091 081 075 055 036 029 018 016
16
+ 16 092 084 095 088 085 072 064 044 026 020 011 010
17
+ 17 085 077 090 081 077 062 053 033 017 013 006 005
18
+ 18 078 069 083 073 068 051 042 023 010 007 002 002
19
+ 19 069 059 075 063 058 039 031 014 004 003 000 000
20
+ 20 060 050 067 053 047 029 021 007 001 001 000 001
21
+ 21 051 040 057 043 036 019 012 003 000 000 002 003
22
+ 22 042 031 047 032 026 010 006 000 001 002 006 007
23
+ 23 032 022 037 022 016 004 002 000 004 005 011 013
24
+ 24 024 014 027 013 008 001 000 002 008 009 017 020
25
+ 25 016 007 018 006 003 000 001 006 014 016 025 029
26
+ 26 009 002 010 002 000 002 005 012 021 023 034 039
27
+ 27 004 000 004 000 001 007 010 019 029 031 044 050
28
+ 28 001 001 001 001 004 014 017 027 038 041 055 061
29
+ 29 000 *** 000 006 010 022 025 036 048 051 066 071
30
+ 30 002 *** 003 013 017 030 033 045 058 061 076 081
31
+ 31 006 *** 008 *** 026 *** 043 055 *** 071 *** 090
@@ -0,0 +1,32 @@
1
+ 01 096 100 096 100 100 098 097 090 078 070 051 045
2
+ 02 099 099 099 099 099 095 093 083 068 059 040 034
3
+ 03 100 096 100 097 096 090 087 075 057 048 030 025
4
+ 04 097 091 098 093 092 083 080 065 045 037 020 017
5
+ 05 093 084 094 087 086 076 071 054 034 026 013 010
6
+ 06 086 076 089 081 079 067 061 043 023 017 007 005
7
+ 07 078 067 082 073 070 057 051 032 014 010 003 002
8
+ 08 069 058 074 064 061 047 040 021 007 004 000 000
9
+ 09 059 048 065 054 051 036 029 012 002 001 000 001
10
+ 10 049 039 056 045 041 026 019 006 000 000 002 003
11
+ 11 040 030 047 035 031 016 011 001 000 001 006 007
12
+ 12 031 021 037 026 022 009 004 000 003 005 011 012
13
+ 13 022 014 028 017 013 003 001 001 008 010 018 019
14
+ 14 015 008 020 010 006 000 000 005 014 016 025 027
15
+ 15 009 003 012 004 002 001 003 011 022 024 034 036
16
+ 16 004 001 006 001 000 004 008 019 030 032 043 045
17
+ 17 001 000 002 000 001 010 015 028 040 041 053 055
18
+ 18 000 002 000 002 006 018 023 037 049 051 062 066
19
+ 19 001 006 001 008 013 028 033 047 058 060 072 076
20
+ 20 004 012 004 015 021 038 043 056 068 070 081 085
21
+ 21 009 021 010 024 032 048 053 065 076 078 089 092
22
+ 22 016 030 018 035 042 059 063 074 084 086 095 097
23
+ 23 024 041 027 046 053 068 072 082 091 093 099 100
24
+ 24 034 053 038 057 063 077 080 089 096 097 100 099
25
+ 25 045 064 050 068 073 084 087 094 099 100 098 096
26
+ 26 056 075 061 077 081 091 092 098 100 099 093 089
27
+ 27 068 084 071 085 088 095 097 100 099 096 086 081
28
+ 28 078 091 081 092 094 098 099 100 095 091 077 072
29
+ 29 087 *** 088 096 097 100 100 097 088 083 067 061
30
+ 30 094 *** 094 099 099 099 099 093 080 073 056 051
31
+ 31 098 *** 098 *** 100 *** 096 086 *** 063 *** 040
32
+
@@ -0,0 +1,61 @@
1
+ #ifndef _CONSTS_
2
+ #define _CONSTS_
3
+
4
+ /* Gaussian gravitational constant */
5
+ #define GAUSSK (0.01720209895)
6
+
7
+ /* values related to PI */
8
+ #ifndef PI
9
+ #define PI (139755218526789.0 / 44485467702853.0)
10
+ #endif
11
+
12
+ #define TWOPI (2.0 * PI)
13
+ #define PIDIV2 (0.5 * PI)
14
+
15
+ /* degrees to radians and radians to degrees */
16
+ #define D2R (PI / 180.0)
17
+ #define R2D (180.0 / PI)
18
+
19
+ /* hours to radians and radians to hours */
20
+ #define H2R (PI / 12.0)
21
+ #define R2H (12.0 / PI)
22
+
23
+ /* arcseconds to radians and radians to arcseconds */
24
+ #define A2R (PI / 648000.0)
25
+ #define R2A (648000.0 / PI)
26
+
27
+ /* AU to km and km to AU */
28
+ #define AU2KM (149597870.66)
29
+ #define KM2AU (1.0 / 149597870.66)
30
+
31
+ /* speed of light in km/s and AU/day */
32
+ #define CKMS (299792.458)
33
+ #define CAUD (CKMS * 86400.0 * KM2AU)
34
+
35
+ /* Earth's angular velocity in rad/s */
36
+ #define EarAngVelRD (6.30038748685432)
37
+
38
+ /* Earth's equatorial radius in km and AU */
39
+ #define EarthRadKM (6378.137)
40
+ #define EarthRadAU (EarthRadKM * KM2AU)
41
+
42
+ /* Earth's flattening factor */
43
+ #define EFlat (1.0 / 298.257)
44
+
45
+ /* JED of standard epoch */
46
+ #define J2000 (2451545.0)
47
+
48
+ /* days in a Julian century */
49
+ #define JulCty (36525.0)
50
+
51
+ /* Earth's gravitational constant */
52
+ #define MUC (2.0 * GAUSSK * GAUSSK / (CAUD * CAUD))
53
+
54
+ /* global state vector variable */
55
+ extern double StateVector[15][15][2][6];
56
+
57
+ extern double obsr_lon;
58
+ extern double obsr_lat;
59
+ extern double obsr_ele;
60
+
61
+ #endif /* _CONSTS_ */
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ # have_func returns false if a C function cannot be found. Sometimes this
4
+ # will be OK (the function changed names between versions) and sometimes it is
5
+ # not so you need to exit without creating the Makefile.
6
+
7
+ abort 'missing malloc()' unless have_func 'malloc'
8
+ abort 'missing free()' unless have_func 'free'
9
+
10
+ # Now we create the Makefile that will install the extension as
11
+ # lib/my_malloc/my_malloc.so.
12
+
13
+ create_makefile 'solunar/solunar'
14
+
@@ -0,0 +1,1959 @@
1
+ /*********************** include files ******************************************************/
2
+ #include <ruby.h>
3
+ #include <astrocon.h>
4
+ #include "stdio.h"
5
+ #include "stdlib.h"
6
+ #include <math.h>
7
+ #include <string.h>
8
+ #include <stdbool.h>
9
+
10
+ /*********************** macro definitions **************************************************/
11
+
12
+ #define SUN 0
13
+ #define MOON 1
14
+ #define RA 23
15
+ #define DEC 33
16
+ #define DATA_NAME "USA"
17
+ #define CLUB_NAME "club"
18
+ #define CLUB_EXT ".txt"
19
+ #define DATA_EXT ".bin"
20
+ #define DST_NAME "USA"
21
+ #define DST_EXT ".txt"
22
+ #define DATA_PATH "./ext/solunar/Data_Files/"
23
+ #define CLUB_PATH "./ext/solunar/Club_Files/"
24
+ #define DST_PATH "./ext/solunar/DST_Files/"
25
+ #define SUN_FILE "./ext/solunar/Source_Files/sun.txt"
26
+ #define MOON_FILE "./ext/solunar/Source_Files/moon.txt"
27
+ #define PHASE_FILE "./ext/solunar/Source_Files/phase.txt"
28
+ #define ILLUM_16_FILE "./ext/solunar/Source_Files/ilum_2016.txt"
29
+ #define ILLUM_17_FILE "./ext/solunar/Source_Files/ilum_2017.txt"
30
+ #define ILLUM_18_FILE "./ext/solunar/Source_Files/ilum_2018.txt"
31
+ #define ILLUM_19_FILE "./ext/solunar/Source_Files/ilum_2019.txt"
32
+ #define ILLUM_20_FILE "./ext/solunar/Source_Files/ilum_2020.txt"
33
+ #define ILLUM_21_FILE "./ext/solunar/Source_Files/ilum_2021.txt"
34
+ #define ILLUM_22_FILE "./ext/solunar/Source_Files/ilum_2022.txt"
35
+ #define ILLUM_23_FILE "./ext/solunar/Source_Files/ilum_2023.txt"
36
+ #define ILLUM_24_FILE "./ext/solunar/Source_Files/ilum_2024.txt"
37
+ #define ILLUM_25_FILE "./ext/solunar/Source_Files/ilum_2025.txt"
38
+ #define ILLUM_26_FILE "./ext/solunar/Source_Files/ilum_2026.txt"
39
+
40
+ #define CLUB_FAIL 1
41
+ #define DATA_FAIL 2
42
+ #define SUN_FAIL 3
43
+ #define MOON_FAIL 4
44
+ #define DTS_FAIL 5
45
+ #define PHASE_FAIL 6
46
+ #define ILLUM_16_FAIL 7
47
+ #define ILLUM_17_FAIL 8
48
+ #define ILLUM_18_FAIL 9
49
+ #define ILLUM_19_FAIL 10
50
+ #define ILLUM_20_FAIL 11
51
+ #define ILLUM_21_FAIL 12
52
+ #define ILLUM_22_FAIL 13
53
+ #define ILLUM_23_FAIL 14
54
+ #define ILLUM_24_FAIL 15
55
+ #define ILLUM_25_FAIL 16
56
+ #define ILLUM_26_FAIL 17
57
+ #define ARG_ERROR 99
58
+ //file information
59
+ #define DATA_FILE_SIZE 4018
60
+ #define JPL_DATE_SIZE 12
61
+ #define PHASE_FILE_SIZE 544
62
+ #define DST_FILE_SIZE 11
63
+ #define RST_MAX_TRIES 50
64
+ #define JDATE_BASE 2457388.5 // January 1, 2016
65
+ #define YES 1
66
+ #define NO 0
67
+ #define MINUTES_PER_DAY (24 * 60)
68
+ //exceptions
69
+ #define NEXT_DAY 1
70
+ #define PREV_DAY 2
71
+ #define NONE_TODAY 3
72
+ #define ROUTINE 4
73
+ #define NEVER_RISE 5
74
+ #define NEVER_SET 6
75
+ #define ERROR 7
76
+ #define RST_ERROR 8
77
+ #define RST_FAIL 9
78
+ //phases
79
+ #define NEW_MOON 1
80
+ #define WAX_CRES 2
81
+ #define FIRST_QTR 3
82
+ #define WAX_GIBB 4
83
+ #define FULL_MOON 5
84
+ #define WAN_GIBB 6
85
+ #define LAST_QTR 7
86
+ #define WAN_CRES 8
87
+
88
+ /*********************** typedefs ***********************************************************/
89
+
90
+ typedef struct {
91
+ double ra;
92
+ double dec;
93
+ } jpl_data;
94
+ typedef struct {
95
+ char date[JPL_DATE_SIZE];
96
+ jpl_data sun;
97
+ jpl_data moon;
98
+ bool dst;
99
+ int phase;
100
+ int phase_time;
101
+ int illum;
102
+ } jpl_type;
103
+ typedef struct {
104
+ int minute;
105
+ int second;
106
+ int exception;
107
+ } time_type;
108
+ typedef struct {
109
+ time_type ris;
110
+ time_type set;
111
+ time_type trn;
112
+ time_type tru;
113
+ } rst_type;
114
+ typedef struct {
115
+ char date[JPL_DATE_SIZE];
116
+ int gmt_offset;
117
+ rst_type sun;
118
+ rst_type moon;
119
+ int moon_phase;
120
+ int phase_time;
121
+ int moon_illum;
122
+ } sol_type;
123
+ typedef struct {
124
+ double start;
125
+ double stop;
126
+ } dst_type;
127
+
128
+ /*********************** constant arrays ****************************************************/
129
+
130
+ const int year_days[11] = {
131
+ 0, // 2016
132
+ 366, // 2017
133
+ 731, // 2018
134
+ 1096, // 2019
135
+ 1461, // 2020
136
+ 1827, // 2021
137
+ 2192, // 2022
138
+ 2557, // 2023
139
+ 2922, // 2024
140
+ 3288, // 2025
141
+ 3653, // 2026
142
+ };
143
+ const int month_days[12] = {
144
+ 0, // JAN
145
+ 31, // FEB
146
+ 59, // MAR
147
+ 90, // APR
148
+ 120, // MAY
149
+ 151, // JUN
150
+ 181, // JUL
151
+ 212, // AUG
152
+ 243, // SEP
153
+ 273, // OCT
154
+ 304, // NOV
155
+ 334, // DEC
156
+ };
157
+ const int leap_days[12] = {
158
+ 0, // JAN
159
+ 31, // FEB
160
+ 60, // MAR
161
+ 91, // APR
162
+ 121, // MAY
163
+ 152, // JUN
164
+ 182, // JUL
165
+ 213, // AUG
166
+ 244, // SEP
167
+ 274, // OCT
168
+ 305, // NOV
169
+ 335, // DEC
170
+ };
171
+ char error_msg[][36] = {
172
+ "Operation Successful",
173
+ "Cannot open Club file",
174
+ "Cannot open Data file",
175
+ "Cannot open Sun file",
176
+ "Cannot open Moon file",
177
+ "Cannot open DST file",
178
+ "Cannot open Phase file",
179
+ "Cannot open 2016 Illumination file",
180
+ "Cannot open 2017 Illumination file",
181
+ "Cannot open 2018 Illumination file",
182
+ "Cannot open 2019 Illumination file",
183
+ "Cannot open 2020 Illumination file",
184
+ "Cannot open 2021 Illumination file",
185
+ "Cannot open 2022 Illumination file",
186
+ "Cannot open 2023 Illumination file",
187
+ "Cannot open 2024 Illumination file",
188
+ "Cannot open 2025 Illumination file",
189
+ "Cannot open 2026 Illumination file"
190
+ };
191
+
192
+ /*********************** function prototypes ************************************************/
193
+
194
+ int TestBuildDataFile(void);
195
+ int BuildDataFile(char*);
196
+ int TestSummary(void);
197
+ int Summary(char*, double, double, int, int, int, char*);
198
+ int TestClubFile(void);
199
+ char* ClubFile(char*, char*, int, double, double, int, int, int, char*, char*);
200
+ double ConvertDate(char*);
201
+ int GetSunData(void);
202
+ int GetMoonData(void);
203
+ int GetDateData(void);
204
+ int GetDstData(char*);
205
+ int GetIllumData(void);
206
+ int GetPhaseData(void);
207
+ int SaveDataFile(char*);
208
+ int Solunar(sol_type*, double, double, double, int, int, char*);
209
+ int GetIllumYear(const char*, int*);
210
+ time_type FmtTime(double);
211
+ void FmtTimeStr(char*, time_type, int);
212
+ time_type AdjustTimes(time_type, time_type, time_type, int);
213
+ // original Heafner functions with some changes
214
+ rst_type RST(FILE*, int, double, double, double);
215
+ static int RST_Interpolate(int, double, double, double, double, double*, double*, double,
216
+ double, double, double, double, double, double, double, double*);
217
+ double deg(double x);
218
+ void GetGST(double, int, double*);
219
+ double amodulo(double, double);
220
+
221
+ /*********************** variable delarations ***********************************************/
222
+
223
+ jpl_type jpl_temp[DATA_FILE_SIZE];
224
+ dst_type dst[DST_FILE_SIZE];
225
+
226
+ /*********************** mode selection *****************************************************/
227
+ /*
228
+ Uuncomment one of these to control whether the executable will enter the Console Mode, to display
229
+ a one cay summary, the Club Mode, to porepare the Club File, or the build Mode, to build a new
230
+ data file from a revised DST file. */
231
+
232
+ //define CONSOLE_MODE
233
+ #define CLUB_MODE
234
+ //#define BUILD_MODE
235
+
236
+ /*********************** Main
237
+
238
+ This is the entry point for the program.
239
+
240
+ RETURN VALUE: EXIT_SUCCESS or Error Code
241
+
242
+ PARAMETERS: Varies depending on mode
243
+ */
244
+ /*#ifdef CONSOLE_MODE
245
+ int main()
246
+ {
247
+ enum { BUILD = 'B', CLUB = 'C', DISPLAY = 'D' };
248
+ int task;
249
+ char line[100];
250
+
251
+ printf("Enter: Club File, Display Summary, Build Data File: ");
252
+ fgets(line, sizeof line, stdin);
253
+ if (line[0] == '\n') strcpy(line, "Club");
254
+ task = line[0];
255
+ switch (task)
256
+ {
257
+ case BUILD:
258
+ case BUILD + 32:
259
+ printf("\nBUILD DATA FILE\n\n");
260
+ TestBuildDataFile();
261
+ break;
262
+ case DISPLAY:
263
+ case DISPLAY + 32:
264
+ printf("\nDISPLAY SUMMARY\n\n");
265
+ TestSummary();
266
+ break;
267
+ default:
268
+ printf("\nCLUB FILE\n\n");
269
+ TestClubFile();
270
+ break;
271
+ }
272
+ return 0;
273
+ }
274
+ #endif*/
275
+
276
+ static VALUE generate(VALUE self, VALUE r_date_str, VALUE r_count, VALUE r_lat,
277
+ VALUE r_lon, VALUE r_gmt_offset, VALUE r_dst_offset, VALUE r_military_time)
278
+ {
279
+ char* result;
280
+ int gmt_offset;
281
+ int dst_time;
282
+ int am_pm;
283
+ int count;
284
+ double lat;
285
+ double lon;
286
+ char *club_name;
287
+ char *date_str;
288
+ char *data_name;
289
+ VALUE ret_v;
290
+
291
+ club_name = "club"; //Constant, as this isn't really used for anything
292
+ date_str = RSTRING_PTR(r_date_str);
293
+ count = NUM2INT(r_count);
294
+ lat = NUM2DBL(r_lat);
295
+ lon = NUM2DBL(r_lon);
296
+ gmt_offset = NUM2INT(r_gmt_offset);
297
+ dst_time = NUM2INT(r_dst_offset);
298
+ am_pm = NUM2INT(r_military_time);
299
+ data_name = "USA"; //Constant, for now
300
+ int outputLength;
301
+ outputLength = count*251;
302
+ char output[outputLength];
303
+ result = ClubFile( club_name, date_str, count, lat, lon,
304
+ gmt_offset, dst_time, am_pm, data_name, output);
305
+ ret_v = rb_str_new2(result);
306
+
307
+ return ret_v;
308
+ }
309
+
310
+ /*#ifdef BUILD_MODE
311
+ int main(int argc, char *argv[])
312
+ {
313
+ return argc < 2? ARG_ERROR : BuildDataFile(argv[1]);
314
+
315
+ }
316
+ #endif*/
317
+
318
+ /*********************** Build Data File Test
319
+
320
+ This function exercises BuildDataFile(). It is used for testing.
321
+
322
+ RETURN VALUE: EXIT_SUCCESS or Error Code
323
+
324
+ PARAMETERS: none
325
+ */
326
+ int TestBuildDataFile()
327
+ {
328
+ int success;
329
+ char line[100];
330
+ char file_name[100];
331
+
332
+ printf("Enter DST/Data File Name: ");
333
+ fgets(line, sizeof line, stdin);
334
+ if (line[0] == '\n') strcpy(file_name, DST_NAME);
335
+ else
336
+ {
337
+ line[strlen(line) - 1] = '\0';
338
+ strcpy(file_name, line);
339
+ }
340
+ success = BuildDataFile(file_name);
341
+ printf("\n%s", error_msg[success]);
342
+ printf("\n\nOK? ");
343
+ fgets(line, sizeof line, stdin);
344
+ return success;
345
+ }
346
+ /*********************** Build Data File
347
+
348
+ This function prepares a the Data file from a number of source data files. If one of the files
349
+ cannot be opened, the program stops there and returns a number indicating the failure.
350
+
351
+ RETURN VALUE: EXIT_SUCCESS or Error Code
352
+
353
+ PARAMETERS: name of DST file and resultant Data File
354
+
355
+ */
356
+ int BuildDataFile(char *file_name)
357
+ {
358
+ int success;
359
+ char data_filename[32];
360
+ char dst_filename[32];
361
+
362
+ strcpy(data_filename, DATA_PATH);
363
+ strcat(data_filename, file_name);
364
+ strcat(data_filename, DATA_EXT);
365
+ strcpy(dst_filename, DST_PATH);
366
+ strcat(dst_filename, file_name);
367
+ strcat(dst_filename, DST_EXT);
368
+
369
+ success = 0;
370
+ if (success == EXIT_SUCCESS) success = GetSunData();
371
+ if (success == EXIT_SUCCESS) success = GetMoonData();
372
+ if (success == EXIT_SUCCESS) success = GetDateData();
373
+ if (success == EXIT_SUCCESS) success = GetDstData(dst_filename);
374
+ if (success == EXIT_SUCCESS) success = GetIllumData();
375
+ if (success == EXIT_SUCCESS) success = GetPhaseData();
376
+ if (success == EXIT_SUCCESS) success = SaveDataFile(data_filename);
377
+ return success;
378
+ }
379
+
380
+ /*********************** Display Summary Test
381
+
382
+ This function exercises Summary(). It is used for testing.
383
+
384
+ RETURN VALUE: EXIT_SUCCESS or Error Code
385
+
386
+ PARAMETERS: none
387
+ */
388
+ int TestSummary(void)
389
+ {
390
+ int dst_time;
391
+ int am_pm;
392
+ char date_str[100];
393
+ char file_name[100];
394
+ char line[1024];
395
+ double lat;
396
+ double lon;
397
+ int gmt_offset;
398
+ int success;
399
+
400
+ printf("Enter Data File name: ");
401
+ fgets(line, sizeof line, stdin);
402
+ if (line[0] == '\n') strcpy(file_name, DATA_NAME);
403
+ else
404
+ {
405
+ line[strlen(line) - 1] = '\0';
406
+ strcpy(file_name, line);
407
+ }
408
+
409
+ printf("Enter latitude (+N/-S, dd.dddd): ");
410
+ fgets(line, sizeof line, stdin);
411
+ if (line[0] == '\n') lat = 34.5082;
412
+ else sscanf(line, "%lf", &lat);
413
+
414
+ printf("Enter longitude (+W/-E, dd.dddd): ");
415
+ fgets(line, sizeof line, stdin);
416
+ if (line[0] == '\n') lon = 82.6500;
417
+ else sscanf(line, "%lf", &lon);
418
+
419
+ printf("Enter offset minutes from GMT (+W/-E): ");
420
+ fgets(line, sizeof line, stdin);
421
+ if (line[0] == '\n') gmt_offset = 5 * 60;
422
+ else sscanf(line, "%i", &gmt_offset);
423
+
424
+ printf("Enter DST time in minutes: ");
425
+ fgets(line, sizeof line, stdin);
426
+ if (line[0] == '\n') dst_time = 60;
427
+ else sscanf(line, "%i", &dst_time);
428
+
429
+ printf("Enter Date - YYYY/MM/DD: ");
430
+ fgets(line, sizeof line, stdin);
431
+ if (line[0] == '\n') strcpy(date_str, "2016/07/04");
432
+ else
433
+ {
434
+ line[strlen(line) - 1] = '\0';
435
+ strcpy(date_str, line);
436
+ }
437
+ printf("24 Hour Format (YES/NO): ");
438
+ fgets(line, sizeof line, stdin);
439
+ am_pm = ((line[0] == 'Y') || (line[0] == 'y')) ? NO : YES;
440
+
441
+ success = Summary(date_str, lat, lon, gmt_offset, dst_time, am_pm, file_name);
442
+
443
+ printf("\n%s", error_msg[success]);
444
+
445
+ printf("\n\nOK? ");
446
+
447
+ fgets(line, sizeof line, stdin);
448
+ return success;
449
+ }
450
+ /*********************** Display Summary
451
+
452
+ This function displays all data for the parameters specified.
453
+
454
+ RETURN VALUE: EXIT_SUCCESS or Error Code
455
+
456
+ PARAMETERS: date (string)
457
+ latitude (+ is north)
458
+ longitude (+ is west)
459
+ offset from GMT in minutes (+ is west)
460
+ daylight savings time change in minutes
461
+ time format desired
462
+ name of the data file
463
+ */
464
+ int Summary(char *date_str, double lat, double lon, int gmt_offset, int dst_time,
465
+ int am_pm, char *data_file)
466
+ {
467
+ sol_type solunar;
468
+ time_type temp;
469
+ double jdate;
470
+ int n;
471
+ int success;
472
+ char s_ris[10];
473
+ char s_trn[10];
474
+ char s_set[10];
475
+ char s_tru[10];
476
+ char m_ris[10];
477
+ char m_trn[10];
478
+ char m_set[10];
479
+ char m_tru[10];
480
+ char p_tim[10];
481
+ char filename[100];
482
+ const char phase[9][16] =
483
+ { "*** ERROR *** ",
484
+ "NEW_MOON ",
485
+ "Waxing Crescent",
486
+ "FIRST QUARTER ",
487
+ "Waxing Gibbous ",
488
+ "FULL MOON ",
489
+ "Waning Gibbous ",
490
+ "LAST QUARTER ",
491
+ "Waning Cescent " };
492
+
493
+ lat *= D2R;
494
+ lon *= D2R;
495
+
496
+ strcpy(filename, DATA_PATH);
497
+ strcat(filename, data_file);
498
+ strcat(filename, DATA_EXT);
499
+ jdate = ConvertDate(date_str);
500
+
501
+ success = Solunar(&solunar, jdate, lat, lon, gmt_offset, dst_time, filename);
502
+ if (success == EXIT_SUCCESS)
503
+ {
504
+ FmtTimeStr(s_ris, solunar.sun.ris, am_pm);
505
+ FmtTimeStr(s_trn, solunar.sun.trn, am_pm);
506
+ FmtTimeStr(s_set, solunar.sun.set, am_pm);
507
+ FmtTimeStr(s_tru, solunar.sun.tru, am_pm);
508
+ FmtTimeStr(m_ris, solunar.moon.ris, am_pm);
509
+ FmtTimeStr(m_trn, solunar.moon.trn, am_pm);
510
+ FmtTimeStr(m_set, solunar.moon.set, am_pm);
511
+ FmtTimeStr(m_tru, solunar.moon.tru, am_pm);
512
+
513
+ printf("\n%s SUN local times (GMT - %i)\n", solunar.date, solunar.gmt_offset);
514
+ printf(" Rise = %s\n", s_ris);
515
+ printf(" Transit = %s\n", s_trn);
516
+ printf(" Set = %s\n", s_set);
517
+ printf(" Tran Under = %s\n", s_tru);
518
+ printf("\n%s MOON local times (GMT - %i)\n", solunar.date, solunar.gmt_offset);
519
+ printf(" Rise = %s\n", m_ris);
520
+ printf(" Transit = %s\n", m_trn);
521
+ printf(" Set = %s\n", m_set);
522
+ printf(" Tran Under = %s\n", m_tru);
523
+
524
+ for (n = 0; n < 8; n++)
525
+ {
526
+ p_tim[n] = ' ';
527
+ }
528
+ p_tim[n] = '\0';
529
+ if (solunar.phase_time != 0)
530
+ {
531
+ temp.minute = solunar.phase_time;
532
+ temp.second = 0;
533
+ temp.exception = 0;
534
+ FmtTimeStr(p_tim, temp, am_pm);
535
+ }
536
+ printf( " %s %s\n %d%% Illuminated\n",
537
+ phase[solunar.moon_phase], p_tim, solunar.moon_illum);
538
+ }
539
+ return success;
540
+ }
541
+
542
+ /*********************** Club File Test
543
+
544
+ This function exercises ClubFile(). It is used for testing.
545
+
546
+ RETURN VALUE: EXIT_SUCCESS or Error Code
547
+
548
+ PARAMETERS: none
549
+ */
550
+ int TestClubFile(void)
551
+ {
552
+ int success;
553
+ int dst_time;
554
+ int am_pm;
555
+ char club_name[100];
556
+ char data_name[100];
557
+ char start_date[100];
558
+ char line[1024];
559
+ double lat;
560
+ double lon;
561
+ int count;
562
+ int gmt_offset;
563
+
564
+ printf("Enter Club Name: ");
565
+ fgets(line, sizeof line, stdin);
566
+ if (line[0] == '\n') strcpy(club_name, CLUB_NAME);
567
+ else
568
+ {
569
+ line[strlen(line) - 1] = '\0';
570
+ strcpy(club_name, line);
571
+ }
572
+ printf("Enter Data File Name: ");
573
+ fgets(line, sizeof line, stdin);
574
+ if (line[0] == '\n') strcpy(data_name, DATA_NAME);
575
+ else
576
+ {
577
+ line[strlen(line) - 1] = '\0';
578
+ strcpy(data_name, line);
579
+ }
580
+ printf("Enter latitude (+N/-S, dd.dddd): ");
581
+ fgets(line, sizeof line, stdin);
582
+ if (line[0] == '\n') lat = 34.5082;
583
+ else sscanf(line, "%lf", &lat);
584
+
585
+ printf("Enter longitude (+W/-E, dd.dddd): ");
586
+ fgets(line, sizeof line, stdin);
587
+ if (line[0] == '\n') lon = 82.6500;
588
+ else sscanf(line, "%lf", &lon);
589
+
590
+ printf("Enter offset minutes from GMT (+W/-E): ");
591
+ fgets(line, sizeof line, stdin);
592
+ if (line[0] == '\n') gmt_offset = 5 * 60;
593
+ else sscanf(line, "%i", &gmt_offset);
594
+
595
+ printf("Enter DST time in minutes: ");
596
+ fgets(line, sizeof line, stdin);
597
+ if (line[0] == '\n') dst_time = 60;
598
+ else sscanf(line, "%i", &dst_time);
599
+
600
+ printf("Enter Starting Date - YYYY/MM/DD: ");
601
+ fgets(line, sizeof line, stdin);
602
+ if (line[0] == '\n') strcpy(start_date, "2016/07/04");
603
+ else
604
+ {
605
+ line[strlen(line) - 1] = '\0';
606
+ strcpy(start_date, line);
607
+ }
608
+
609
+ printf("Enter number of days to be listed: ");
610
+ fgets(line, sizeof line, stdin);
611
+ if (line[0] == '\n') count = 1;
612
+ else sscanf(line, "%i", &count);
613
+
614
+ printf("24 Hour Format (YES/NO): ");
615
+ fgets(line, sizeof line, stdin);
616
+ am_pm = ((line[0] == 'Y') || (line[0] == 'y')) ? NO : YES;
617
+
618
+ //success = ClubFile(club_name, start_date, count, lat, lon, gmt_offset, dst_time, am_pm, data_name);
619
+
620
+ printf("\n%s", error_msg[success]);
621
+ printf("\n\nOK? ");
622
+ fgets(line, sizeof line, stdin);
623
+
624
+ return success;
625
+ }
626
+ /*********************** Prepare Club Data File
627
+
628
+ This function prepares a text file with a list of values for the date range specified.
629
+
630
+ RETURN VALUE: EXIT_SUCCESS or Error Code
631
+
632
+ PARAMETERS: name of Club File
633
+ starting date (string)
634
+ number of days to be listed
635
+ latitude (+ is north)
636
+ longitude (+ is weast)
637
+ offset from GMT in minutes (+ is west)
638
+ daylight savings time change in minutes
639
+ name of Data File
640
+ */
641
+ char* ClubFile(char *club_name, char *start_date, int count, double lat, double lon,
642
+ int gmt_offset, int dst_time, int am_pm, char *data_name, char *output)
643
+ {
644
+ FILE *file;
645
+ int i;
646
+ int n;
647
+ int success;
648
+ double jdate;
649
+ time_type temp;
650
+ sol_type solunar;
651
+ char s_ris[10];
652
+ char s_trn[10];
653
+ char s_set[10];
654
+ char s_tru[10];
655
+ char m_ris[10];
656
+ char m_trn[10];
657
+ char m_set[10];
658
+ char m_tru[10];
659
+ char p_tim[10];
660
+ char data_filename[100];
661
+ char club_filename[100];
662
+ const char phase[9][16] =
663
+ { "*** ERROR *** ",
664
+ "New Moon ",
665
+ "Waxing Crescent",
666
+ "First Quarter ",
667
+ "Waxing Gibbous ",
668
+ "Full Moon ",
669
+ "Waning Gibbous ",
670
+ "Last Quarter ",
671
+ "Waning Crescent" };
672
+
673
+ lat *= D2R;
674
+ lon *= D2R;
675
+
676
+ strcpy(club_filename, CLUB_PATH);
677
+ strcat(club_filename, club_name);
678
+ strcat(club_filename, CLUB_EXT);
679
+ strcpy(data_filename, DATA_PATH);
680
+ strcat(data_filename, data_name);
681
+ strcat(data_filename, DATA_EXT);
682
+ jdate = ConvertDate(start_date);
683
+
684
+ for (i = 0; i < count; i++)
685
+ {
686
+ success = Solunar(&solunar, jdate + i, lat, lon, gmt_offset, dst_time, data_filename);
687
+ if (success == EXIT_SUCCESS)
688
+ {
689
+ FmtTimeStr(s_ris, solunar.sun.ris, am_pm);
690
+ FmtTimeStr(s_trn, solunar.sun.trn, am_pm);
691
+ FmtTimeStr(s_set, solunar.sun.set, am_pm);
692
+ FmtTimeStr(s_tru, solunar.sun.tru, am_pm);
693
+ FmtTimeStr(m_ris, solunar.moon.ris, am_pm);
694
+ FmtTimeStr(m_trn, solunar.moon.trn, am_pm);
695
+ FmtTimeStr(m_set, solunar.moon.set, am_pm);
696
+ FmtTimeStr(m_tru, solunar.moon.tru, am_pm);
697
+
698
+ for (n = 0; n < 8; n ++)
699
+ {
700
+ p_tim[n] = ' ';
701
+ }
702
+ p_tim[n] = '\0';
703
+ if (solunar.phase_time != 0)
704
+ {
705
+ temp.minute = solunar.phase_time;
706
+ temp.second = 0;
707
+ temp.exception = 0;
708
+
709
+ FmtTimeStr(p_tim, temp, am_pm);
710
+ }
711
+ char charout[250];
712
+ sprintf(charout,"%s, %s, %s, %s, %s, %s, %s, %s, %s, %i, %s, %s, %i%%\n",
713
+ solunar.date, s_ris, s_trn, s_set, s_tru, m_ris, m_trn, m_set, m_tru,
714
+ solunar.gmt_offset, phase[solunar.moon_phase], p_tim, solunar.moon_illum);
715
+ if(strlen(output) == 0){
716
+ strcpy(output,charout);
717
+ }
718
+ else{
719
+ strcat(output,";");
720
+ strcat(output,charout);
721
+ }
722
+ }
723
+ }
724
+
725
+ return output;
726
+
727
+ }
728
+ /*********************** Convert Date
729
+
730
+ This function returns the jdate from a string containing the desired date in a YYYY-MM-DD format.
731
+
732
+ RETURN VALUE: jdate
733
+ 0.0 if text date is not valid
734
+
735
+ PARAMETERS: pointer to date string (yyyy/mm/dd
736
+ */
737
+ double ConvertDate(char* string)
738
+ {
739
+ int m[] = {31,28,31,30,31,30,31,31,30,31,30,31};
740
+ int l[] = {31,29,31,30,31,30,31,31,30,31,30,31};
741
+ int year;
742
+ int month;
743
+ int day;
744
+ int error;
745
+ double result;
746
+
747
+ error = NO;
748
+ year = atoi(string);
749
+ month = atoi(string + 5);
750
+ day = atoi(string + 8);
751
+ if ((year < 2016) || (year > 2026)) error = YES;
752
+ if ((month < 1) || (month > 12)) error = YES;
753
+ if ((day < 1) || ((year % 4 == 0) && (day > l[month - 1]))) error = YES;
754
+ if ((day < 1) || ((year % 4 != 0) && (day > m[month - 1]))) error = YES;
755
+ if (error == NO)
756
+ {
757
+ result = JDATE_BASE;
758
+ result += year_days[year - 2016];
759
+ result += year % 4 == 0? leap_days[month - 1]: month_days[month - 1];
760
+ result += day - 1;
761
+ }
762
+ else
763
+ {
764
+ result = 0.0;
765
+ }
766
+ return result;
767
+ }
768
+ /*********************** Get Sun Data
769
+
770
+ This function gets the sun's JPL values for right ascension and declination values from the JPL
771
+ data in sun.txt and puts them into jpl_temp[].
772
+
773
+ RETURN VALUE: EXIT_SUCCESS or Error Code
774
+
775
+ PARAMETERS: none
776
+ */
777
+ int GetSunData(void)
778
+ {
779
+ FILE *file;
780
+ int n;
781
+ int success;
782
+ char buffer[100];
783
+
784
+ file = fopen(SUN_FILE, "r");
785
+ if (file != NULL)
786
+ {
787
+ for (n = 0; n < DATA_FILE_SIZE; n++)
788
+ {
789
+ fgets(buffer, 100, file);
790
+ jpl_temp[n].sun.ra = atof(buffer + RA);
791
+ jpl_temp[n].sun.dec = atof(buffer + DEC);
792
+ }
793
+ fclose(file);
794
+ success = EXIT_SUCCESS;
795
+ }
796
+ else
797
+ {
798
+ success = SUN_FAIL;
799
+ }
800
+ return success;
801
+ }
802
+
803
+ /*********************** Get Moon Data
804
+
805
+ This function gets the moon's JPL values for right ascension and declination values from the JPL
806
+ data in sun.txt and puts them into jpl_temp[].
807
+
808
+ RETURN VALUE: EXIT_SUCCESS or Error Code
809
+
810
+ PARAMETERS: none
811
+ */
812
+ int GetMoonData(void)
813
+ {
814
+ FILE* file;
815
+ int n;
816
+ int success;
817
+ char buffer[100];
818
+
819
+ file = fopen(MOON_FILE, "r");
820
+ if (file != NULL)
821
+ {
822
+ for (n = 0; n < DATA_FILE_SIZE; n++)
823
+ {
824
+ fgets(buffer, 100, file);
825
+ jpl_temp[n].moon.ra = atof(buffer + RA);
826
+ jpl_temp[n].moon.dec = atof(buffer + DEC);
827
+ }
828
+ fclose(file);
829
+ success = EXIT_SUCCESS;
830
+ }
831
+ else
832
+ {
833
+ success = MOON_FAIL;
834
+ }
835
+ return success;
836
+ }
837
+
838
+ /*********************** Get Date String
839
+
840
+ This function gets the date string from the JPL data in moon.txt and puts it into jpl_temp[].
841
+ This operation could have been done as part of GetMoonData() or GetSunData(), but is separated
842
+ for clarity.
843
+
844
+ RETURN VALUE: EXIT_SUCCESS or Error Code
845
+
846
+ PARAMETERS: none
847
+ */
848
+ int GetDateData(void)
849
+ {
850
+ FILE* file;
851
+ int n;
852
+ int i;
853
+ int success;
854
+ char buffer[100];
855
+
856
+ file = fopen(MOON_FILE, "r");
857
+ if (file != NULL)
858
+ {
859
+ for (n = 0; n < DATA_FILE_SIZE; n++)
860
+ {
861
+ fgets(buffer, 100, file);
862
+ for (i = 0; i < JPL_DATE_SIZE - 1; i++)
863
+ {
864
+ jpl_temp[n].date[i] = buffer[i + 1];
865
+ }
866
+ jpl_temp[n].date[i] = '\0';
867
+ }
868
+ fclose(file);
869
+ success = EXIT_SUCCESS;
870
+ }
871
+ else
872
+ {
873
+ success = MOON_FAIL;
874
+ }
875
+ return success;
876
+ }
877
+
878
+ /*********************** Get Daylight Savings Time Data
879
+
880
+ For every element of the jpl_temp[] array, this function determines whether or not the associated
881
+ date is subject to daylight savinhgs time and the dst member is updated.
882
+
883
+ RETURN VALUE: EXIT_SUCCESS or Error Code
884
+
885
+ PARAMETERS: none
886
+ */
887
+ int GetDstData(char *filename)
888
+ {
889
+ FILE* file;
890
+ char buffer[100];
891
+ int n;
892
+ int y;
893
+ int success;
894
+ double jdate;
895
+
896
+ file = fopen(filename, "r");
897
+ if (file != NULL)
898
+ {
899
+ for (y = 0; y < DST_FILE_SIZE; y++)
900
+ {
901
+ fgets(buffer, 100, file);
902
+ dst[y].start = ConvertDate(buffer);
903
+ dst[y].stop = ConvertDate(buffer + 12);
904
+ }
905
+ for (n = 0; n < DATA_FILE_SIZE; n++)
906
+ {
907
+ jdate = JDATE_BASE + n;
908
+ jpl_temp[n].dst = NO;
909
+ for (y = 0; y < (sizeof dst / sizeof(dst_type)); y++)
910
+ {
911
+ if (jdate < dst[y].stop)
912
+ {
913
+ if (jdate >= dst[y].start)
914
+ {
915
+ jpl_temp[n].dst = YES;
916
+ }
917
+ break;
918
+ }
919
+ }
920
+ }
921
+ fclose(file);
922
+ success = EXIT_SUCCESS;
923
+ }
924
+ else
925
+ {
926
+ success = DTS_FAIL;
927
+ }
928
+ return success;
929
+ }
930
+ /*********************** Get Moon Phase Data
931
+
932
+ This function gets the moon's phase data from the phase.txt file and puts it into jpl_temp[].
933
+
934
+ RETURN VALUE: EXIT_SUCCESS or Error Code
935
+
936
+ PARAMETERS: none
937
+ */
938
+ int GetPhaseData(void)
939
+ {
940
+ FILE* file;
941
+ bool match;
942
+ int c;
943
+ int j;
944
+ int i;
945
+ int n;
946
+ int phase;
947
+ int success;
948
+ char date[11];
949
+ int minute;
950
+ char buffer[100];
951
+
952
+ j = 0;
953
+ for (n = 0; n < DATA_FILE_SIZE; n++)
954
+ {
955
+ jpl_temp[n].phase = 0;
956
+ jpl_temp[n].phase_time = 0;
957
+ }
958
+ file = fopen(PHASE_FILE, "r");
959
+ if (file != NULL)
960
+ {
961
+ for (n = 0; n < PHASE_FILE_SIZE; n++)
962
+ {
963
+ fgets(buffer, 100, file);
964
+ i = 0;
965
+ while (buffer[i++] != '\t');
966
+ for (c = 0; c < 11; c++)
967
+ {
968
+ date[c] = buffer[i] == ' ' ? '-' : buffer[i];
969
+ i++;
970
+ }
971
+ i ++;
972
+ minute = atoi(buffer + i) * 60;
973
+ minute += atoi(buffer + i + 3);
974
+ if (minute == 0)
975
+ {
976
+ minute = 24 * 60;
977
+ }
978
+ match = NO;
979
+ while (match == NO)
980
+ {
981
+ for (c = 0; c < 11; c++)
982
+ {
983
+ if (date[c] != jpl_temp[j].date[c])
984
+ {
985
+ break;
986
+ }
987
+ }
988
+ if (c == 11)
989
+ {
990
+ match = YES;
991
+ }
992
+ else
993
+ {
994
+ j++;
995
+ }
996
+ }
997
+ if (buffer[2] == 'w') jpl_temp[j].phase = NEW_MOON;
998
+ else if (buffer[2] == 'r') jpl_temp[j].phase = FIRST_QTR;
999
+ else if (buffer[2] == 'l') jpl_temp[j].phase = FULL_MOON;
1000
+ else jpl_temp[j].phase = LAST_QTR;
1001
+ jpl_temp[j].phase_time = minute;
1002
+ }
1003
+ fclose(file);
1004
+ success = EXIT_SUCCESS;
1005
+
1006
+ // for each element of the jpl array:
1007
+ // record the phase based on the last major phases
1008
+ // record the the time of the last major phase
1009
+ phase = FULL_MOON; // 12/25/2015 phase
1010
+ minute = (11 * 60)+ 11; // 12/25/2015 Full Moon time
1011
+ for (n = 0; n < DATA_FILE_SIZE; n++)
1012
+ {
1013
+ if (jpl_temp[n].phase == 0)
1014
+ {
1015
+ jpl_temp[n].phase = phase + 1;
1016
+ }
1017
+ else
1018
+ {
1019
+ phase = jpl_temp[n].phase;
1020
+ }
1021
+ }
1022
+ }
1023
+ else
1024
+ {
1025
+ success = PHASE_FAIL;
1026
+ }
1027
+ return success;
1028
+ }
1029
+
1030
+ /*********************** Get Moon Illumination Percentage Data
1031
+
1032
+ This function gets the moon's percent illumination data from Ilum 20xx.txt files and puts it
1033
+ into jpl_temp[].
1034
+
1035
+ RETURN VALUE: EXIT_SUCCESS or Error Code
1036
+
1037
+ PARAMETERS: none
1038
+ */
1039
+ int GetIllumData(void)
1040
+ {
1041
+ int index;
1042
+ int success;
1043
+
1044
+ index = 0;
1045
+ success = EXIT_SUCCESS;
1046
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_16_FILE, &index);
1047
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_17_FILE, &index);
1048
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_18_FILE, &index);
1049
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_19_FILE, &index);
1050
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_20_FILE, &index);
1051
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_21_FILE, &index);
1052
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_22_FILE, &index);
1053
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_23_FILE, &index);
1054
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_24_FILE, &index);
1055
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_25_FILE, &index);
1056
+ if (success == EXIT_SUCCESS) success = GetIllumYear(ILLUM_26_FILE, &index);
1057
+ return success;
1058
+ }
1059
+
1060
+ /*********************** Save Data File
1061
+
1062
+ After the daylight savings data, date string and the right ascension and declination values for
1063
+ the sun and moon plus mone phase and illumination have been placed in jpl.temp[], this function
1064
+ writes the jpl data to the Data File.
1065
+
1066
+ RETURN VALUE: EXIT_SUCCESS or Error Code
1067
+
1068
+ PARAMETERS: filepath of Data File
1069
+ */
1070
+ int SaveDataFile(char *filename)
1071
+ {
1072
+ FILE *file;
1073
+ int success;
1074
+
1075
+ file = fopen(filename, "wb");
1076
+ if (file != NULL)
1077
+ {
1078
+ fwrite(jpl_temp, sizeof(jpl_type), DATA_FILE_SIZE, file);
1079
+ fclose(file);
1080
+ success = EXIT_SUCCESS;
1081
+ }
1082
+ else
1083
+ {
1084
+ success = DATA_FAIL;
1085
+ }
1086
+ return success;
1087
+ }
1088
+
1089
+ /*********************** Solunar
1090
+
1091
+ This function returns all the informatin required by the Knockdown program.
1092
+
1093
+ As to the phases of the moon:
1094
+
1095
+ The JPL file stores all data by GMT date. Unless the GMT offset time is 0, the local date
1096
+ overlaps parts of two GMT dates:
1097
+
1098
+ East of Greenwich, the local date overlaps that part of the previous GMT date where the
1099
+ GMT time is within [gmt_offset] minutes before midnight; the local date overlaps the current
1100
+ GMT date the rest of the day.
1101
+
1102
+ West of Greenwich, the local date overlaps that part of the following GMT date where the
1103
+ GMT time is within [gmt_offset] minutes after midnight; the local date overlaps the current
1104
+ GMT date the rest of the day.
1105
+
1106
+ The Primary moon phases are reported in local time and date. Use the GMT date where the
1107
+ time of the moon phase overlaps the current local date.
1108
+
1109
+
1110
+ RETURN VALUE: EXIT_SUCCESS or Error Code
1111
+
1112
+ PARAMETERS: sol_type structure with sun, moon, date, and DST adjusted GME offset information
1113
+ julian date
1114
+ latitude (+ is north)
1115
+ longitude (+ is west)
1116
+ minutes easr or west of GMT (+ is west)
1117
+ DST time in minutes
1118
+ filepath of Data File
1119
+ */
1120
+ int Solunar(sol_type *result, double jdate, double lat, double lon,
1121
+ int gmt_offset, int dst_time, char *filename)
1122
+ {
1123
+ enum {p_day, c_day, f_day};
1124
+ int n;
1125
+ int index;
1126
+ int success;
1127
+ FILE *file;
1128
+ jpl_type jpl[3];
1129
+ rst_type times_p;
1130
+ rst_type times;
1131
+ rst_type times_f;
1132
+ int phase_time;
1133
+ int months[13][5] = {
1134
+ { 'J', 'a', 'n', '0', '1' },
1135
+ { 'F', 'e', 'b', '0', '2' },
1136
+ { 'M', 'a', 'r', '0', '3' },
1137
+ { 'A', 'p', 'r', '0', '4' },
1138
+ { 'M', 'a', 'y', '0', '5' },
1139
+ { 'J', 'u', 'n', '0', '6' },
1140
+ { 'J', 'u', 'l', '0', '7' },
1141
+ { 'A', 'u', 'g', '0', '8' },
1142
+ { 'S', 'e', 'p', '0', '9' },
1143
+ { 'O', 'c', 't', '1', '0' },
1144
+ { 'N', 'o', 'v', '1', '1' },
1145
+ { 'D', 'e', 'c', '1', '2' },
1146
+ { 0, 0, 0, '?', '?' } };
1147
+
1148
+ //lon = -lon;
1149
+
1150
+ // get date
1151
+ index = (int)(floor(jdate) - floor(JDATE_BASE));
1152
+ file = fopen(filename, "rb");
1153
+ if (file != NULL)
1154
+ {
1155
+ fseek(file, ((index - 1) * sizeof(jpl_type)), SEEK_SET);
1156
+ fread(&jpl[0], sizeof(jpl_type), 3, file);
1157
+ for (n = 0; n < 12; n++)
1158
+ {
1159
+ if ( (jpl[c_day].date[5] == months[n][0])
1160
+ && (jpl[c_day].date[6] == months[n][1])
1161
+ && (jpl[c_day].date[7] == months[n][2]) )
1162
+ {
1163
+ break;
1164
+ }
1165
+ }
1166
+ result->date[0] = jpl[c_day].date[0];
1167
+ result->date[1] = jpl[c_day].date[1];
1168
+ result->date[2] = jpl[c_day].date[2];
1169
+ result->date[3] = jpl[c_day].date[3];
1170
+ result->date[4] = '-';
1171
+ result->date[5] = months[n][3];
1172
+ result->date[6] = months[n][4];
1173
+ result->date[7] = '-';
1174
+ result->date[8] = jpl[c_day].date[9];
1175
+ result->date[9] = jpl[c_day].date[10];
1176
+ result->date[10] = '\0';
1177
+
1178
+ // adjust gmt offset for dst
1179
+ if ((dst_time != 0) && (jpl[c_day].dst == YES))
1180
+ {
1181
+ gmt_offset -= dst_time;
1182
+ }
1183
+ result->gmt_offset = gmt_offset;
1184
+
1185
+ // get values for the sun
1186
+ times_p = RST(file, SUN, jdate - 1, lat, lon);
1187
+ times = RST(file, SUN, jdate, lat, lon);
1188
+ times_f = RST(file, SUN, jdate + 1, lat, lon);
1189
+ result->sun.ris = AdjustTimes(times_p.ris, times.ris, times_f.ris, gmt_offset);
1190
+ result->sun.trn = AdjustTimes(times_p.trn, times.trn, times_f.trn, gmt_offset);
1191
+ result->sun.set = AdjustTimes(times_p.set, times.set, times_f.set, gmt_offset);
1192
+
1193
+ // get values for the moon
1194
+ times_p = RST(file, MOON, jdate - 1, lat, lon);
1195
+ times = RST(file, MOON, jdate, lat, lon);
1196
+ times_f = RST(file, MOON, jdate + 1, lat, lon);
1197
+ result->moon.ris = AdjustTimes(times_p.ris, times.ris, times_f.ris, gmt_offset);
1198
+ result->moon.trn = AdjustTimes(times_p.trn, times.trn, times_f.trn, gmt_offset);
1199
+ result->moon.set = AdjustTimes(times_p.set, times.set, times_f.set, gmt_offset);
1200
+
1201
+ // get value for sun and moon transit underfoot ...
1202
+ if (lon < 0) lon += PI;
1203
+ else lon -= PI;
1204
+
1205
+ // ... sun
1206
+ times_p = RST(file, SUN, jdate - 1, lat, lon);
1207
+ times = RST(file, SUN, jdate, lat, lon);
1208
+ times_f = RST(file, SUN, jdate + 1, lat, lon);
1209
+ result->sun.tru = AdjustTimes(times_p.trn, times.trn, times_f.trn, gmt_offset);
1210
+
1211
+ // ... moon
1212
+ times_p = RST(file, MOON, jdate - 1, lat, lon);
1213
+ times = RST(file, MOON, jdate, lat, lon);
1214
+ times_f = RST(file, MOON, jdate + 1, lat, lon);
1215
+ result->moon.tru = AdjustTimes(times_p.trn, times.trn, times_f.trn, gmt_offset);
1216
+
1217
+ fclose(file);
1218
+
1219
+ // if western hemisphere or Britian Summer Time
1220
+ if (gmt_offset > 0)
1221
+ {
1222
+ // if the following Greenwich day has a primary phase at a time that is during the
1223
+ // current local day, use the phase from the following Greenwich day
1224
+ if ( (jpl[f_day].phase_time != 0)
1225
+ && (jpl[f_day].phase_time <= abs(gmt_offset)) )
1226
+ {
1227
+ result->moon_phase = jpl[f_day].phase;
1228
+ phase_time = jpl[f_day].phase_time;
1229
+ }
1230
+ // if the current Greenwich day has a primary phase at a time that is not during the
1231
+ // current local day, use the phase from the following Greenwich day
1232
+ else if ( (jpl[c_day].phase_time != 0)
1233
+ && (jpl[c_day].phase_time <= abs(gmt_offset)) )
1234
+ {
1235
+ result->moon_phase = jpl[f_day].phase;
1236
+ phase_time = jpl[f_day].phase_time;
1237
+ }
1238
+ // if it is not necessary to use the phase from the following GMT day, use the phase
1239
+ // from the current GMT day
1240
+ else
1241
+ {
1242
+ result->moon_phase = jpl[c_day].phase;
1243
+ phase_time = jpl[c_day].phase_time;
1244
+ }
1245
+ if (phase_time != 0.0)
1246
+ {
1247
+ phase_time += 24 * 60;
1248
+ phase_time -= abs(gmt_offset);
1249
+ if (phase_time > MINUTES_PER_DAY)
1250
+ {
1251
+ phase_time -= 24 * 60;
1252
+ }
1253
+ }
1254
+ result->phase_time = phase_time;
1255
+ }
1256
+ // if eastern hemisphere
1257
+ else if (gmt_offset < 0)
1258
+ {
1259
+ // if the previous Greenwich day has a primary phase at a time that is during the
1260
+ // current local day, use the phase from the following Greenwich day
1261
+ if ( (jpl[p_day].phase_time != 0)
1262
+ && ((MINUTES_PER_DAY - jpl[p_day].phase_time) <= abs(gmt_offset)))
1263
+ {
1264
+ result->moon_phase = jpl[p_day].phase;
1265
+ phase_time = jpl[p_day].phase_time;
1266
+ }
1267
+ // if the current Greenwich day has a primary phase at a time that is not during the
1268
+ // current local day, use the hase from the previous Greenwich day
1269
+ else if ( (jpl[c_day].phase_time != 0)
1270
+ && ((MINUTES_PER_DAY - jpl[c_day].phase_time) <= abs(gmt_offset)))
1271
+ {
1272
+ result->moon_phase = jpl[p_day].phase;
1273
+ phase_time = jpl[p_day].phase_time;
1274
+ }
1275
+ // if it is not necessary to use the phase from the previous GMT day, use the phase
1276
+ // from the current GMT day
1277
+ else
1278
+ {
1279
+ result->moon_phase = jpl[c_day].phase;
1280
+ phase_time = jpl[c_day].phase_time;
1281
+ }
1282
+ if (phase_time != 0.0)
1283
+ {
1284
+ phase_time += abs(gmt_offset);
1285
+ {
1286
+ if (phase_time > MINUTES_PER_DAY)
1287
+ {
1288
+ phase_time -= MINUTES_PER_DAY;
1289
+ }
1290
+ }
1291
+ }
1292
+ result->phase_time = phase_time;
1293
+ }
1294
+ // if the gmt offset is 0, use the phase from the current Greenwich day
1295
+ else
1296
+ {
1297
+ result->moon_phase = jpl[c_day].phase;
1298
+ phase_time = jpl[c_day].phase_time;
1299
+ result->phase_time = phase_time;
1300
+ }
1301
+ result->moon_illum = jpl[c_day].illum;
1302
+ success = EXIT_SUCCESS;
1303
+ }
1304
+ else
1305
+ {
1306
+ //rb_eval_string("puts 'No file found at: '+`pwd`");
1307
+ success = DATA_FAIL;
1308
+ }
1309
+ return success;
1310
+ }
1311
+
1312
+ /*********************** Get Moon Illumination Percentage Data for One Year
1313
+
1314
+ This function processes the moon's percent illumination data from the specified file and places
1315
+ it into jpl_temp[] for one year. Parameter index is kept up to date as this function is called
1316
+ multiple times - one for each year.
1317
+
1318
+ RETURN VALUE: EXIT_SUCCESS or Error Code
1319
+
1320
+ PARAMETERS: current file
1321
+ index into jpl_temp[]
1322
+ */
1323
+ int GetIllumYear(const char *filename, int *index)
1324
+ {
1325
+ FILE* file;
1326
+ char buffer[31][102];
1327
+ int col[] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
1328
+ int m;
1329
+ int d;
1330
+ int n;
1331
+ int success;
1332
+
1333
+ file = fopen(filename, "r");
1334
+ if (file != NULL)
1335
+ {
1336
+ for (n = 0; n < 31; n++)
1337
+ {
1338
+ fgets(buffer[n], 102, file);
1339
+ }
1340
+ fclose(file);
1341
+ for (m = 0; m < 12; m++)
1342
+ {
1343
+ for (d = 0; d < 31; d++)
1344
+ {
1345
+ if (buffer[d][col[m]] == '*')
1346
+ {
1347
+ break;
1348
+ }
1349
+ else
1350
+ {
1351
+ jpl_temp[*index].illum = atoi(buffer[d] + col[m]);
1352
+ (*index) ++;
1353
+ }
1354
+ }
1355
+ }
1356
+ success = EXIT_SUCCESS;
1357
+ }
1358
+ else
1359
+ {
1360
+ success = EXIT_FAILURE;
1361
+ }
1362
+ return success;
1363
+ }
1364
+
1365
+ /*********************** Format the Time Structure
1366
+
1367
+ This function formats a decimal time (H.hhhh) into minutes and seconds. Internal to the
1368
+ program, time of day is kept in interger munites. To avoid floating point, seconds are a
1369
+ separate field and is used only for development and desting.
1370
+
1371
+ RETURN VALUE: formated time structure
1372
+
1373
+ PARAMETERS: decimal time
1374
+ */
1375
+ time_type FmtTime(double d_time)
1376
+ {
1377
+ time_type result;
1378
+ double d_minute;
1379
+ double d_second;
1380
+ double i_minute;
1381
+ double i_second;
1382
+ double temp;
1383
+
1384
+ d_minute = d_time * 60;
1385
+ i_minute = floor(d_minute);
1386
+ d_second = (d_minute - i_minute) * 60;
1387
+ i_second = floor(d_second);
1388
+ temp = (d_second - i_second);
1389
+ if (temp >= 0.5)
1390
+ {
1391
+ i_second += 1.0;
1392
+ }
1393
+ if (i_second == 60)
1394
+ {
1395
+ i_second = 0;
1396
+ i_minute += 1;
1397
+ }
1398
+ result.minute = (int)d_minute;
1399
+ result.second = (int)d_second;
1400
+ result.exception = NULL;
1401
+
1402
+ return result;
1403
+ }
1404
+
1405
+ /*********************** Format a Time String
1406
+
1407
+ This function formats a string in the format hh:mm:ss from a time_type structure.
1408
+
1409
+ RETURN VALUE: none
1410
+
1411
+ PARAMETERS: pointer to destination string
1412
+ time-type structure to be formatted
1413
+ flag indicating whether format should 24 hour (with seconds) or am/pm
1414
+ */
1415
+ void FmtTimeStr(char *string, time_type times, int am_pm)
1416
+ {
1417
+ int n;
1418
+ int hour;
1419
+ int min;
1420
+ char a_p;
1421
+ const char exception[9][9] = {
1422
+ " ",
1423
+ " ",
1424
+ " NONE ",
1425
+ " ",
1426
+ " DARK ",
1427
+ " BRIGHT ",
1428
+ " ",
1429
+ "ERROR 1",
1430
+ "ERROR 2" };
1431
+
1432
+ if (times.exception >= NONE_TODAY)
1433
+ {
1434
+ sprintf(string, "%s", exception[times.exception - 1]);
1435
+ }
1436
+ else
1437
+ {
1438
+ if (am_pm == YES)
1439
+ {
1440
+ if (times.second >= 30) times.minute += 1;
1441
+ if (times.minute >= MINUTES_PER_DAY) times.minute = MINUTES_PER_DAY - 1;
1442
+ hour = times.minute / 60;
1443
+ a_p = hour >= 12? 'p': 'a';
1444
+ if (hour > 12) hour -= 12;
1445
+ if (hour == 0) hour = 12;
1446
+ min = times.minute % 60;
1447
+ sprintf(string, "%2d:%2d %cm", hour, min, a_p);
1448
+ if (string[3] == ' ') string[3] = '0';
1449
+ }
1450
+ else
1451
+ {
1452
+ hour = times.minute / 60;
1453
+ min = times.minute % 60;
1454
+ sprintf(string, "%2d:%2d:%2d", hour, min, times.second);
1455
+ for (n = 0; n < 8; n++)
1456
+ {
1457
+ if (string[n] == ' ') string[n] = '0';
1458
+ }
1459
+ }
1460
+ }
1461
+ }
1462
+
1463
+ /*********************** Adjust Times
1464
+
1465
+ For an explanation of this function,see the Adjust Times files in the project folder.
1466
+
1467
+ RETURN VALUE: adjusted time structure
1468
+
1469
+ PARAMETERS: time sStructure for the previous day
1470
+ time structure for the Current Day
1471
+ time structure for the Following Day
1472
+ offset from GMT (hours west)
1473
+ */
1474
+ time_type AdjustTimes( time_type previous_day, time_type current_day,
1475
+ time_type following_day, int gmt_offset)
1476
+ {
1477
+ #define TIME_BEFORE_MIDNIGHT(x) (MINUTES_PER_DAY - x)
1478
+ #define TIME_AFTER_MIDNIGHT(x) x
1479
+ time_type result;
1480
+ int special;
1481
+ int temp_1;
1482
+ int temp_2;
1483
+
1484
+ // if in the western hemisphere or Britan Summer Time
1485
+ if (gmt_offset > 0)
1486
+ {
1487
+ special = abs(current_day.minute - following_day.minute) > (MINUTES_PER_DAY / 2) ? YES : NO;
1488
+ if ((current_day.exception > ROUTINE) || (following_day.exception > ROUTINE))
1489
+ {
1490
+ if (current_day.exception > ERROR) result = following_day;
1491
+ else result = current_day;
1492
+ result.minute += MINUTES_PER_DAY;
1493
+ result.minute -= gmt_offset;
1494
+ result.minute %= MINUTES_PER_DAY;
1495
+ }
1496
+ else if (TIME_AFTER_MIDNIGHT(current_day.minute) >= gmt_offset)
1497
+ {
1498
+ result = current_day;
1499
+ result.minute -= gmt_offset;
1500
+ }
1501
+ else if (TIME_AFTER_MIDNIGHT(following_day.minute) < gmt_offset)
1502
+ {
1503
+ result = following_day;
1504
+ result.minute += MINUTES_PER_DAY;
1505
+ result.minute -= gmt_offset;
1506
+ }
1507
+ else if (special == YES)
1508
+ {
1509
+ result = current_day;
1510
+ temp_1 = (current_day.minute + MINUTES_PER_DAY - gmt_offset) % MINUTES_PER_DAY;
1511
+ temp_2 = (following_day.minute + MINUTES_PER_DAY - gmt_offset) % MINUTES_PER_DAY;
1512
+ result.minute = (temp_1 + temp_2) / 2;
1513
+ }
1514
+ else
1515
+ {
1516
+ result.exception = NONE_TODAY;
1517
+ }
1518
+ }
1519
+ //if in eastern hemisphere
1520
+ else if (gmt_offset < 0)
1521
+ {
1522
+ gmt_offset = abs(gmt_offset);
1523
+ special = abs(previous_day.minute - current_day.minute) > (MINUTES_PER_DAY / 2)? YES: NO;
1524
+ if ((current_day.exception > ROUTINE) || (previous_day.exception > ROUTINE))
1525
+ {
1526
+ if (previous_day.exception > ERROR) result = current_day;
1527
+ else result = previous_day;
1528
+ result.minute += gmt_offset;
1529
+ result.minute %= MINUTES_PER_DAY;
1530
+ }
1531
+ else if (TIME_BEFORE_MIDNIGHT(previous_day.minute) <= gmt_offset)
1532
+ {
1533
+ result = previous_day;
1534
+ result.minute += gmt_offset;
1535
+ result.minute %= MINUTES_PER_DAY;
1536
+ }
1537
+ else if ( (TIME_BEFORE_MIDNIGHT(previous_day.minute) > gmt_offset)
1538
+ && (TIME_BEFORE_MIDNIGHT(current_day.minute) > gmt_offset) )
1539
+ {
1540
+ result = current_day;
1541
+ result.minute += gmt_offset;
1542
+ }
1543
+ else if (special == YES)
1544
+ {
1545
+ result = current_day;
1546
+ temp_1 = (previous_day.minute + gmt_offset) % MINUTES_PER_DAY;
1547
+ temp_2 = (current_day.minute + gmt_offset) % MINUTES_PER_DAY;
1548
+ result.minute = (temp_1 + temp_2) / 2;
1549
+ }
1550
+ else
1551
+ {
1552
+ result.exception = NONE_TODAY;
1553
+ }
1554
+ }
1555
+ else
1556
+ {
1557
+ result = current_day;
1558
+ }
1559
+ return result;
1560
+ }
1561
+
1562
+ /*********************** Rise Set Transit Transit Underfoot
1563
+
1564
+ This function is the heart of the original Heafner code. It has been substantially changed as
1565
+ follows:
1566
+
1567
+ 1) The original function got latitude and longitude data from file scope variables obser_lat and
1568
+ obser_lon. Those have been replaced by parameters lat and lon.
1569
+
1570
+ 2) The original function returned results as text strings. These have been replaced by a singgle
1571
+ rst_type structure which is comprised of time type structures. Each time type strucuture
1572
+ includes exception codes.
1573
+
1574
+ 3) The original function reported exceptions (object never rises or sets, event occurs previous
1575
+ or following day) as text strings. These have been replaced by the exceptions member of the
1576
+ structure.
1577
+
1578
+ 4) The rsflag has been repurposed to show the exception.
1579
+
1580
+ 5) The original function got the ra[] and dec[] arrays as parameters. These are now determined
1581
+ from the JPL file.
1582
+
1583
+ 6) The original function had delta t as a parameter. This is now a fixed value of 69 which is
1584
+ average between the 2016 value of 68.5 and the 2020 value of 69.5.
1585
+
1586
+ 7) Added a fudge factor to z0 to make moon rise and set times agree with published data.
1587
+
1588
+ RETURN VALUE: RST structure
1589
+
1590
+ PARAMETERS: handle to the cata file - already opened.
1591
+ object - SUN or MOON
1592
+ julian date
1593
+ latitude
1594
+ longitude
1595
+ */
1596
+ rst_type RST(FILE *file, int object, double jed, double lat, double lon)
1597
+ {
1598
+ int rsflag, c;
1599
+ double h0, cosh0, newm, oldm, m, m0, m1, m2;
1600
+ double ristime, settime, trntime, gast0;
1601
+ double d1, d2, d3, r1, r2, r3;
1602
+ double deltat;
1603
+ double ra[3];
1604
+ double dec[3];
1605
+ double z0;
1606
+ double hp;
1607
+ double sd;
1608
+ int index;
1609
+ int rst_tries;
1610
+ rst_type result;
1611
+ jpl_type jpl[3];
1612
+
1613
+ deltat = 69;
1614
+ index = (int)(floor(jed) - floor(JDATE_BASE));
1615
+ fseek(file, ((index - 1) * sizeof(jpl_type)), SEEK_SET);
1616
+ fread(&jpl[0], sizeof(jpl_type), 3, file);
1617
+ if (object == SUN)
1618
+ {
1619
+ ra[0] = D2R * jpl[0].sun.ra;
1620
+ dec[0] = D2R * jpl[0].sun.dec;
1621
+ ra[1] = D2R * jpl[1].sun.ra;
1622
+ dec[1] = D2R * jpl[1].sun.dec;
1623
+ ra[2] = D2R * jpl[2].sun.ra;
1624
+ dec[2] = D2R * jpl[2].sun.dec;
1625
+ z0 = D2R * deg(90.34 + 0.16);
1626
+ }
1627
+ else
1628
+ {
1629
+ ra[0] = D2R * jpl[0].moon.ra;
1630
+ dec[0] = D2R * jpl[0].moon.dec;
1631
+ ra[1] = D2R * jpl[1].moon.ra;
1632
+ dec[1] = D2R * jpl[1].moon.dec;
1633
+ ra[2] = D2R * jpl[2].moon.ra;
1634
+ dec[2] = D2R * jpl[2].moon.dec;
1635
+ hp = D2R * deg(0.444156);
1636
+ sd = asin(0.272493 * sin(hp));
1637
+ z0 = D2R * deg(90.34) + sd - hp;
1638
+ z0 -= 0.00275; // fudge factor
1639
+ }
1640
+ /* Make sure the ra[]'s are in continuous order */
1641
+
1642
+ if ((ra[1] < ra[0]) && (ra[2] > ra[1])) {
1643
+ ra[1] = ra[1] + TWOPI;
1644
+ ra[2] = ra[2] + TWOPI;
1645
+ }
1646
+ else if ((ra[1] > ra[0]) && (ra[2] < ra[1])) {
1647
+ ra[2] = ra[2] + TWOPI;
1648
+ }
1649
+
1650
+ r1 = ra[1] - ra[0];
1651
+ r2 = ra[2] - ra[1];
1652
+ r3 = r2 - r1;
1653
+ d1 = dec[1] - dec[0];
1654
+ d2 = dec[2] - dec[1];
1655
+ d3 = d2 - d1;
1656
+
1657
+ rsflag = 0;
1658
+ cosh0 = (cos(z0) - sin(lat) * sin(dec[1])) / (cos(lat) * cos(dec[1]));
1659
+ if (cosh0 < -1.0)
1660
+ {
1661
+ // Object - never sets
1662
+ rsflag = NEVER_SET;
1663
+ }
1664
+ else if (cosh0 > 1.0)
1665
+ {
1666
+ // Object never rises
1667
+ rsflag = NEVER_RISE;
1668
+ }
1669
+
1670
+ GetGST(jed, 1, &gast0);
1671
+
1672
+ m0 = (ra[1] - lon - gast0) / TWOPI;
1673
+ m0 = amodulo(m0, 1.0);
1674
+
1675
+ if (rsflag == 0)
1676
+ {
1677
+ h0 = acos(cosh0);
1678
+ h0 = amodulo(h0, PI);
1679
+ m1 = m0 - h0 / TWOPI;
1680
+ m1 = amodulo(m1, 1.0);
1681
+ m2 = m0 + h0 / TWOPI;
1682
+ m2 = amodulo(m2, 1.0);
1683
+
1684
+ // Rising
1685
+ oldm = m1;
1686
+ c = 1;
1687
+ rst_tries = RST_Interpolate(c, z0, oldm, gast0, deltat, ra, dec,
1688
+ r1, r2, r3, d1, d2, d3, lat, lon, &newm);
1689
+ if (rst_tries == RST_MAX_TRIES)
1690
+ {
1691
+ result.ris.exception = RST_ERROR;
1692
+ }
1693
+ else if (rst_tries > RST_MAX_TRIES)
1694
+ {
1695
+ result.ris.exception = RST_FAIL;
1696
+ }
1697
+ else
1698
+ {
1699
+ m = newm;
1700
+ ristime = 24.0 * m;
1701
+
1702
+ if (ristime > 24.0) {
1703
+ ristime = ristime - 24.0;
1704
+ // Event occurs the following day
1705
+ result.ris = FmtTime(ristime);
1706
+ result.ris.exception = NEXT_DAY;
1707
+ }
1708
+ else if (ristime < 0.0) {
1709
+ ristime = ristime + 24.0;
1710
+ // Event occurs the previous day
1711
+ result.ris = FmtTime(ristime);
1712
+ result.ris.exception = PREV_DAY;
1713
+ }
1714
+ else {
1715
+ result.ris = FmtTime(ristime);
1716
+ }
1717
+ }
1718
+ // Setting
1719
+ oldm = m2;
1720
+ c = 1;
1721
+ rst_tries = RST_Interpolate(c, z0, oldm, gast0, deltat, ra, dec,
1722
+ r1, r2, r3, d1, d2, d3, lat, lon, &newm);
1723
+ if (rst_tries == RST_MAX_TRIES)
1724
+ {
1725
+ result.set.exception = RST_ERROR;
1726
+ }
1727
+ else if (rst_tries > RST_MAX_TRIES)
1728
+ {
1729
+ result.set.exception = RST_FAIL;
1730
+ }
1731
+ else
1732
+ {
1733
+ m = newm;
1734
+ settime = 24.0 * m;
1735
+ if (settime > 24.0)
1736
+ {
1737
+ settime = settime - 24.0;
1738
+ result.set = FmtTime(settime);
1739
+ result.set.exception = NEXT_DAY;
1740
+ }
1741
+ else if (settime < 0.0) {
1742
+ settime = settime + 24.0;
1743
+ result.set = FmtTime(settime);
1744
+ result.set.exception = PREV_DAY;
1745
+ }
1746
+ else {
1747
+ result.set = FmtTime(settime);
1748
+ }
1749
+ }
1750
+ }
1751
+
1752
+ else
1753
+ {
1754
+ result.set = FmtTime(0);
1755
+ result.ris = FmtTime(0);
1756
+ result.set.exception = rsflag;
1757
+ result.ris.exception = rsflag;
1758
+ }
1759
+ // Transiting
1760
+ oldm = m0;
1761
+ c = 0;
1762
+ rst_tries = RST_Interpolate(c, z0, oldm, gast0, deltat, ra, dec,
1763
+ r1, r2, r3, d1, d2, d3, lat, lon, &newm);
1764
+ if (rst_tries == RST_MAX_TRIES)
1765
+ {
1766
+ result.trn.exception = RST_ERROR;
1767
+ }
1768
+ if (rst_tries > RST_MAX_TRIES)
1769
+ {
1770
+ result.trn.exception = RST_FAIL;
1771
+ }
1772
+ else
1773
+ {
1774
+ m = newm;
1775
+ trntime = 24.0 * m;
1776
+ if (trntime > 24.0) {
1777
+ trntime = trntime - 24.0;
1778
+ result.trn = FmtTime(trntime);
1779
+ result.trn.exception = NEXT_DAY;
1780
+ }
1781
+ else if (trntime < 0.0) {
1782
+ trntime = trntime + 24.0;
1783
+ result.trn = FmtTime(trntime);
1784
+ result.trn.exception = PREV_DAY;
1785
+ }
1786
+ else {
1787
+ result.trn = FmtTime(trntime);
1788
+ }
1789
+ }
1790
+ return result;
1791
+ }
1792
+
1793
+ /*********************** Interpolation required by RST()
1794
+
1795
+ This is original Heafner code. For explanation, see the originalfunction in astrolib.c.
1796
+ The only modification is that the original function got latitude and longitude data from
1797
+ file scope variables obser_lat and obser_lon. Those have been replaced by parameters lat
1798
+ and lon.
1799
+
1800
+ RETURN VALUE: count of inerations in do loop
1801
+
1802
+ PARAMETERS: lat latitude
1803
+ lon longitude
1804
+ (see original function in astrolib to describe others)
1805
+ */
1806
+ static int RST_Interpolate(int c, double z0, double oldm, double gast0,
1807
+ double deltat, double *ra, double *dec, double r1, double r2, double r3,
1808
+ double d1, double d2, double d3, double lat, double lon, double *newm) {
1809
+
1810
+ double alpha, dm, h, gast, delta, alt, n;
1811
+ int count;
1812
+
1813
+ count = 0;
1814
+ *newm = oldm;
1815
+ do {
1816
+ count ++;
1817
+ if (count > RST_MAX_TRIES)
1818
+ {
1819
+ break;
1820
+ }
1821
+ gast = gast0 + 6.300388093 * (*newm);
1822
+ gast = amodulo(gast, TWOPI);
1823
+ n = *newm + deltat / 86400.0;
1824
+ alpha = ra[1] + 0.5 * n * (r1 + r2 + n * r3);
1825
+ alpha = amodulo(alpha, TWOPI);
1826
+ delta = dec[1] + 0.5 * n * (d1 + d2 + n * d3);
1827
+ h = gast + lon - alpha;
1828
+ alt = asin(sin(delta) * sin(lat) + cos(delta) * cos(lat) * cos(h));
1829
+ if (c == 0) {
1830
+ /* h must satisfy -PI <= h <= PI */
1831
+ h = amodulo(h, TWOPI);
1832
+ if (h > PI) {
1833
+ h = h - TWOPI;
1834
+ }
1835
+ dm = -h / TWOPI;
1836
+ }
1837
+ else {
1838
+ dm = (alt - PIDIV2 + z0) / (TWOPI * cos(delta) * cos(lat) * sin(h));
1839
+ }
1840
+ *newm = (*newm) + dm;
1841
+
1842
+
1843
+ } while (fabs(dm) >= 1e-15);
1844
+ if ((*newm >= 2.0) || (*newm <= -1.0))
1845
+ {
1846
+ count = RST_MAX_TRIES;
1847
+ }
1848
+ return count;
1849
+ }
1850
+
1851
+ /*********************** Convert Degrees
1852
+
1853
+ This function cnverts degrees in the format dd.mmss to decimal degrees.
1854
+ It is original Heafner code with no changes
1855
+
1856
+ RETURN VALUE: decimal degrees
1857
+
1858
+ PARAMETERS: degrees in format dD.MMSS
1859
+ */
1860
+ double deg(double x) {
1861
+
1862
+ double dd, d, fixdd, ddfixdd;
1863
+
1864
+ if (x == 0.0) return (0.0);
1865
+
1866
+ dd = fabs(x);
1867
+ fixdd = floor(dd);
1868
+ ddfixdd = dd - fixdd + 5.0e-10; /* fudge factor */
1869
+ d = fixdd + floor(100.0 * ddfixdd) / 60.0;
1870
+ d = d + (10000.0 * ddfixdd - 100.0 * floor(100.0 * ddfixdd)) / 3600.0;
1871
+
1872
+ return ((x / dd) * d);
1873
+ }
1874
+
1875
+ /*********************** Get Grenwich Sidereal Time
1876
+
1877
+ This function computes Sidereal time (in radians) from the Julian date.It is original Heafner
1878
+ code excdpt:
1879
+
1880
+ 1) The original was siginicantly more complicated in that it computed apparent sidereal time.
1881
+ We don't require that kind of (sub-minute) accuracy, so we will use mean sidereal time. All
1882
+ code required to calculate apparent sidereal time has been removed.
1883
+
1884
+ 2) The parameter that specified mean or apparent sideereal time has been removed.
1885
+
1886
+ 3) The original had logic such that saved the time and apparent flag. If the call was the
1887
+ same as the previous call, the function would simply return with no changes. That would force
1888
+ the calling function to save the result for use if it happened to call this function twice in
1889
+ a row with the same date. That may have been useful when being called by some functions not
1890
+ used in our application, but where it is called in RST, the result (gast0) is not saved. The
1891
+ result was that an unitialized value was sent to RST_Interpolate() which caused it to fail.
1892
+ That logic has been removed.
1893
+
1894
+ RETURN VALUE: none
1895
+
1896
+ PARAMETERS: Juilian date
1897
+ address of result
1898
+ */
1899
+ void GetGST(double jed, int s, double *gst) {
1900
+
1901
+ double T;
1902
+
1903
+ T = (jed - J2000) / JulCty;
1904
+
1905
+ /* compute GMST in seconds */
1906
+ *gst = 67310.54841 + T * ((876600.0 * 3600.0 + 8640184.812866)
1907
+ + T * (0.093104 + T * (-0.0000062)));
1908
+
1909
+ /* convert to radians */
1910
+ *gst = amodulo(*gst / 3600.0, 24.0) * H2R;
1911
+ *gst = amodulo(*gst, TWOPI);
1912
+ }
1913
+
1914
+ /*********************** Calculate the modulo of an angle
1915
+
1916
+ This function calculates the module of an angle to the specified base. It us used with values in
1917
+ radians with either PI or TWOPI
1918
+
1919
+ RETURN VALUE: modulo of the angle
1920
+
1921
+ PARAMETERS: the angle
1922
+ the base
1923
+ */
1924
+ double amodulo(double a, double b) {
1925
+
1926
+ double x;
1927
+
1928
+ x = a - b * floor(a / b);
1929
+ return (x);
1930
+ }
1931
+
1932
+ /*************************** Ruby interface code *******************************************************/
1933
+
1934
+ static VALUE
1935
+ test_function(VALUE self, VALUE number) {
1936
+ VALUE v;
1937
+ long i;
1938
+ i = FIX2LONG(number);
1939
+ i = i*2;
1940
+ v = LONG2FIX(i);
1941
+ return v;
1942
+ }
1943
+
1944
+ /* This function initializes the new Solunar object - the names should match, and capitalization seems to come from Ruby magic.
1945
+ * A "Value" is C/Ruby.h/C++ speak for a Ruby object. In this case, with the rb_intern stuff, that object is of the class "Solunar" and is registered as such.
1946
+ * Registration is pure ruby magic. rb_define_method uses this, of the format (root_object - always the thing declared before, name to be registered as, function name, number of arguements to pass)
1947
+ * Caveat to the above: Functions that will return to Ruby always are of type "Value", and always have a first object, of type value, that does something likely important - but exactly what, I couldn't tell you...
1948
+ */
1949
+
1950
+ void
1951
+ Init_solunar(void) {
1952
+ VALUE cSolunar;
1953
+
1954
+ cSolunar = rb_const_get(rb_cObject, rb_intern("Solunar"));
1955
+
1956
+ rb_define_method(cSolunar, "multi", test_function, 1);
1957
+ rb_define_method(cSolunar, "generate", generate, 7);
1958
+ }
1959
+