solunar 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+