voruby 1.1.1 → 2.0.0

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.
Files changed (257) hide show
  1. data/Rakefile.rb +107 -224
  2. data/lib/misc.rb +1 -0
  3. data/lib/misc/misc.rb +60 -0
  4. data/lib/misc/propertyfile.rb +31 -0
  5. data/lib/symphony.rb +1 -0
  6. data/lib/symphony/symphony.rb +247 -0
  7. data/lib/voruby.rb +186 -0
  8. data/lib/voruby/active_votable/active_votable.rb +468 -347
  9. data/lib/voruby/adql/1.0/adql.rb +2418 -0
  10. data/lib/voruby/adql/support.rb +2 -0
  11. data/lib/voruby/misc.rb +351 -0
  12. data/lib/voruby/misc/connection_monitor.rb +97 -0
  13. data/lib/voruby/misc/libxml_ext.rb +121 -0
  14. data/lib/voruby/misc/rexml_ext.rb +223 -0
  15. data/lib/voruby/resolver/resolver.rb +12 -0
  16. data/lib/voruby/resolver/sesame.rb +299 -0
  17. data/lib/voruby/sky_query/sky_query.rb +192 -0
  18. data/lib/voruby/stc/1.10/coords.rb +2272 -0
  19. data/lib/voruby/stc/1.10/region.rb +892 -0
  20. data/lib/voruby/stc/1.10/stc.rb +3271 -0
  21. data/lib/voruby/stc/1.30/stc.rb +8666 -0
  22. data/lib/voruby/stc/support.rb +2 -0
  23. data/lib/voruby/ucd/ucd.rb +173 -0
  24. data/lib/voruby/voevent/1.1/voevent.rb +1124 -0
  25. data/lib/voruby/voevent/support.rb +5 -0
  26. data/lib/voruby/votable/1.0/votable.rb +1807 -0
  27. data/lib/voruby/votable/1.1/votable.rb +2100 -0
  28. data/lib/voruby/votable/votable.rb +305 -0
  29. data/lib/voruby/wesix/wesix.rb +491 -0
  30. data/lib/voruby/xlink/1.2/xlink.rb +21 -0
  31. data/test/voruby/active_votable/complex.vot +60 -0
  32. data/test/voruby/active_votable/error.vot +6 -0
  33. data/test/voruby/active_votable/large.vot +130040 -0
  34. data/test/voruby/active_votable/simple1.vot +38 -0
  35. data/test/voruby/active_votable/simple2.vot +38 -0
  36. data/test/voruby/active_votable/test.rb +193 -0
  37. data/test/voruby/adql/1.0/adql-alias.sql +1 -0
  38. data/test/voruby/adql/1.0/adql-alias.xml +26 -0
  39. data/test/voruby/adql/1.0/adql-avg.sql +1 -0
  40. data/test/voruby/adql/1.0/adql-avg.xml +31 -0
  41. data/test/voruby/adql/1.0/adql-circle.sql +1 -0
  42. data/test/voruby/adql/1.0/adql-circle.xml +46 -0
  43. data/test/voruby/adql/1.0/adql-expr.sql +1 -0
  44. data/test/voruby/adql/1.0/adql-expr.xml +34 -0
  45. data/test/voruby/adql/1.0/adql-function.sql +1 -0
  46. data/test/voruby/adql/1.0/adql-function.xml +41 -0
  47. data/test/voruby/adql/1.0/adql-group.sql +1 -0
  48. data/test/voruby/adql/1.0/adql-group.xml +51 -0
  49. data/test/voruby/adql/1.0/adql-having.sql +1 -0
  50. data/test/voruby/adql/1.0/adql-having.xml +25 -0
  51. data/test/voruby/adql/1.0/adql-like.sql +1 -0
  52. data/test/voruby/adql/1.0/adql-like.xml +17 -0
  53. data/test/voruby/adql/1.0/adql-order.sql +1 -0
  54. data/test/voruby/adql/1.0/adql-order.xml +37 -0
  55. data/test/voruby/adql/1.0/adql-simple.sql +1 -0
  56. data/test/voruby/adql/1.0/adql-simple.xml +12 -0
  57. data/test/voruby/adql/1.0/adql-top.sql +1 -0
  58. data/test/voruby/adql/1.0/adql-top.xml +33 -0
  59. data/test/voruby/adql/1.0/test.rb +2220 -0
  60. data/test/voruby/misc/test.rb +32 -0
  61. data/test/voruby/resolver/sesame/test.rb +56 -0
  62. data/test/voruby/sky_query/test.rb +107 -0
  63. data/test/voruby/stc/1.10/coords_test.rb +3704 -0
  64. data/test/voruby/stc/1.10/region_test.rb +993 -0
  65. data/test/voruby/stc/1.10/stc-catalog-entry-location.xml +112 -0
  66. data/test/voruby/stc/1.10/stc-obs-data-location.xml +126 -0
  67. data/test/voruby/stc/1.10/stc-region-circle.xml +5 -0
  68. data/test/voruby/stc/1.10/stc-region-convex.xml +11 -0
  69. data/test/voruby/stc/1.10/stc-region-convexhull.xml +5 -0
  70. data/test/voruby/stc/1.10/stc-region-ellipse.xml +7 -0
  71. data/test/voruby/stc/1.10/stc-region-intersection.xml +25 -0
  72. data/test/voruby/stc/1.10/stc-region-negation.xml +7 -0
  73. data/test/voruby/stc/1.10/stc-region-polygon.xml +13 -0
  74. data/test/voruby/stc/1.10/stc-region-sector.xml +6 -0
  75. data/test/voruby/stc/1.10/stc-region-union.xml +25 -0
  76. data/test/voruby/stc/1.10/stc-resource-profile.xml +60 -0
  77. data/test/voruby/stc/1.10/stc-search-location.xml +54 -0
  78. data/test/voruby/stc/1.10/stc_test.rb +4626 -0
  79. data/test/voruby/stc/1.30/stc-catalog-entry-location.xml +210 -0
  80. data/test/voruby/stc/1.30/stc-obs-data-location-arecibo.xml +353 -0
  81. data/test/voruby/stc/1.30/stc-obs-data-location-fits.xml +250 -0
  82. data/test/voruby/stc/1.30/stc-obs-data-location-xlink.xml +63 -0
  83. data/test/voruby/stc/1.30/stc-obs-data-location.xml +216 -0
  84. data/test/voruby/stc/1.30/stc-resource-profile-unusual-ref-pos.xml +39 -0
  85. data/test/voruby/stc/1.30/stc-resource-profile.xml +129 -0
  86. data/test/voruby/stc/1.30/stc-search-location-arecibo.xml +86 -0
  87. data/test/voruby/stc/1.30/stc-search-location.xml +101 -0
  88. data/test/voruby/stc/1.30/test.rb +6274 -0
  89. data/test/voruby/ucd/test.rb +48 -0
  90. data/test/voruby/voevent/1.1/test.rb +812 -0
  91. data/test/{voevent/voevent_v1_1.xml → voruby/voevent/1.1/voevent.xml} +2 -2
  92. data/test/voruby/voregistry/0.3/test.rb +137 -0
  93. data/test/voruby/votable/1.0/test.rb +714 -0
  94. data/test/voruby/votable/1.0/votable.basic.xml +660 -0
  95. data/test/voruby/votable/1.0/votable.html +86 -0
  96. data/test/voruby/votable/1.0/votable.ns.xml +56 -0
  97. data/test/voruby/votable/1.1/test.rb +785 -0
  98. data/test/voruby/votable/1.1/votable.basic.xml +38 -0
  99. data/test/voruby/votable/1.1/votable.html +86 -0
  100. data/test/voruby/votable/1.1/votable.ns.xml +56 -0
  101. data/test/voruby/votable/test.rb +15 -0
  102. data/test/voruby/wesix/test.rb +268 -0
  103. data/test/voruby/wesix/testr.fits +28 -0
  104. metadata +234 -247
  105. data/REQUIREMENTS +0 -6
  106. data/lib/voruby/active_votable/loader.rb +0 -5
  107. data/lib/voruby/adql/adql.rb +0 -2787
  108. data/lib/voruby/adql/ext.rb +0 -14
  109. data/lib/voruby/adql/loader.rb +0 -6
  110. data/lib/voruby/adql/operations.rb +0 -54
  111. data/lib/voruby/adql/parser.rb +0 -160
  112. data/lib/voruby/adql/transforms.rb +0 -573
  113. data/lib/voruby/ext.rb +0 -17
  114. data/lib/voruby/loader.rb +0 -4
  115. data/lib/voruby/misc/propertyfile.rb +0 -36
  116. data/lib/voruby/plastic/applications.rb +0 -174
  117. data/lib/voruby/plastic/constants.rb +0 -30
  118. data/lib/voruby/plastic/loader.rb +0 -10
  119. data/lib/voruby/plastic/plastic.rb +0 -1
  120. data/lib/voruby/resources/conesearch/conesearch.rb +0 -9
  121. data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +0 -55
  122. data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +0 -50
  123. data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +0 -72
  124. data/lib/voruby/resources/conesearch/loader.rb +0 -4
  125. data/lib/voruby/resources/loader.rb +0 -50
  126. data/lib/voruby/resources/nodes.rb +0 -190
  127. data/lib/voruby/resources/openskynode/loader.rb +0 -4
  128. data/lib/voruby/resources/openskynode/openskynode.rb +0 -9
  129. data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +0 -54
  130. data/lib/voruby/resources/sia/loader.rb +0 -5
  131. data/lib/voruby/resources/sia/sia.rb +0 -9
  132. data/lib/voruby/resources/sia/sia_v0_6.rb +0 -90
  133. data/lib/voruby/resources/sia/sia_v0_7.rb +0 -89
  134. data/lib/voruby/resources/sia/sia_v1_0.rb +0 -122
  135. data/lib/voruby/resources/stsci.rb +0 -59
  136. data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +0 -195
  137. data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +0 -158
  138. data/lib/voruby/resources/vodataservice/loader.rb +0 -5
  139. data/lib/voruby/resources/vodataservice/vodataservice.rb +0 -9
  140. data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +0 -189
  141. data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +0 -163
  142. data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +0 -221
  143. data/lib/voruby/resources/voregistry/loader.rb +0 -4
  144. data/lib/voruby/resources/voregistry/voregistry.rb +0 -9
  145. data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +0 -40
  146. data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +0 -30
  147. data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +0 -86
  148. data/lib/voruby/resources/voresource/loader.rb +0 -17
  149. data/lib/voruby/resources/voresource/voresource.rb +0 -9
  150. data/lib/voruby/resources/voresource/voresource_v0_10.rb +0 -327
  151. data/lib/voruby/resources/voresource/voresource_v0_9.rb +0 -405
  152. data/lib/voruby/resources/voresource/voresource_v1_0.rb +0 -230
  153. data/lib/voruby/services/ext.rb +0 -11
  154. data/lib/voruby/services/gestalt/footprint.rb +0 -95
  155. data/lib/voruby/services/gestalt/wcs_fixer.rb +0 -105
  156. data/lib/voruby/services/gestalt/wesix.rb +0 -155
  157. data/lib/voruby/services/loader.rb +0 -7
  158. data/lib/voruby/services/registry/registry.rb +0 -53
  159. data/lib/voruby/services/resolver/resolver.rb +0 -35
  160. data/lib/voruby/services/schema/schema.rb +0 -644
  161. data/lib/voruby/sesame/loader.rb +0 -6
  162. data/lib/voruby/sesame/sesame_v1_0.rb +0 -64
  163. data/lib/voruby/simple/loader.rb +0 -6
  164. data/lib/voruby/simple/parameters.rb +0 -196
  165. data/lib/voruby/simple/sap.rb +0 -446
  166. data/lib/voruby/spacetime/loader.rb +0 -3
  167. data/lib/voruby/spacetime/spacetime.rb +0 -607
  168. data/lib/voruby/stc/coords_v1_20.rb +0 -900
  169. data/lib/voruby/stc/loader.rb +0 -55
  170. data/lib/voruby/stc/region_v1_20.rb +0 -274
  171. data/lib/voruby/stc/stc_v1_20.rb +0 -1196
  172. data/lib/voruby/util.rb +0 -27
  173. data/lib/voruby/voevent/loader.rb +0 -7
  174. data/lib/voruby/voevent/voevent_v1_0.rb +0 -213
  175. data/lib/voruby/voevent/voevent_v1_1.rb +0 -196
  176. data/lib/voruby/votables/chandra.rb +0 -373
  177. data/lib/voruby/votables/data.rb +0 -179
  178. data/lib/voruby/votables/galex.rb +0 -377
  179. data/lib/voruby/votables/int.rb +0 -354
  180. data/lib/voruby/votables/libxml_parser.rb +0 -411
  181. data/lib/voruby/votables/libxml_votable.rb +0 -67
  182. data/lib/voruby/votables/loader.rb +0 -10
  183. data/lib/voruby/votables/meta.rb +0 -763
  184. data/lib/voruby/votables/misc.rb +0 -51
  185. data/lib/voruby/votables/nsa.rb +0 -410
  186. data/lib/voruby/votables/rexml_parser.rb +0 -408
  187. data/lib/voruby/votables/rexml_votable.rb +0 -67
  188. data/lib/voruby/votables/sdss.rb +0 -356
  189. data/lib/voruby/votables/transforms.rb +0 -388
  190. data/lib/voruby/votables/tree.rb +0 -45
  191. data/lib/voruby/votables/types.rb +0 -391
  192. data/lib/voruby/votables/votable.rb +0 -687
  193. data/test/active_votable/database.yml +0 -6
  194. data/test/active_votable/test.vot +0 -168492
  195. data/test/active_votable/unittest.rb +0 -41
  196. data/test/adql/test1.adql +0 -49
  197. data/test/adql/test2.adql +0 -51
  198. data/test/adql/test3.adql +0 -81
  199. data/test/adql/test4.adql +0 -53
  200. data/test/adql/test5.adql +0 -55
  201. data/test/adql/test6.adql +0 -18
  202. data/test/adql/test7.adql +0 -48
  203. data/test/adql/unittest.rb +0 -1672
  204. data/test/plastic/test.rb +0 -44
  205. data/test/plastic/test.vot +0 -5385
  206. data/test/plastic/unittest.rb +0 -66
  207. data/test/resources/conesearch/conesearch_v0_3.xml +0 -31
  208. data/test/resources/conesearch/conesearch_v1_0.xml +0 -86
  209. data/test/resources/conesearch/unittest_v0_3.rb +0 -22
  210. data/test/resources/conesearch/unittest_v1_0.rb +0 -24
  211. data/test/resources/openskynode/open_sky_node_v0_1.xml +0 -32
  212. data/test/resources/openskynode/unittest_v0_1.rb +0 -31
  213. data/test/resources/sia/simple_image_access_v0_7.xml +0 -36
  214. data/test/resources/sia/simple_image_access_v1_0.xml +0 -122
  215. data/test/resources/sia/unittest_v0_7.rb +0 -24
  216. data/test/resources/sia/unittest_v1_0.rb +0 -29
  217. data/test/resources/stsci.xml +0 -336
  218. data/test/resources/unittest_stsci.rb +0 -25
  219. data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +0 -128
  220. data/test/resources/vodataservice/data_collection_resource_v0_5.xml +0 -54
  221. data/test/resources/vodataservice/data_collection_resource_v1_0.xml +0 -117
  222. data/test/resources/vodataservice/data_service_resource_v1_0.xml +0 -115
  223. data/test/resources/vodataservice/sky_service_resource_v0_10.xml +0 -45
  224. data/test/resources/vodataservice/table_service_resource_v1_0.xml +0 -122
  225. data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +0 -60
  226. data/test/resources/vodataservice/unittest_v0_5.rb +0 -126
  227. data/test/resources/vodataservice/unittest_v1_0.rb +0 -151
  228. data/test/resources/voregistry/authority_resource_v0_3.xml +0 -20
  229. data/test/resources/voregistry/authority_resource_v1_0.xml +0 -82
  230. data/test/resources/voregistry/registry_service_v0_3.xml +0 -20
  231. data/test/resources/voregistry/registry_service_v1_0.xml +0 -107
  232. data/test/resources/voregistry/unittest_v0_3.rb +0 -31
  233. data/test/resources/voregistry/unittest_v1_0.rb +0 -34
  234. data/test/resources/voresource/organisation_resource_v1_0.xml +0 -90
  235. data/test/resources/voresource/resource_organisation_v0_10.xml +0 -22
  236. data/test/resources/voresource/resource_service_v0_10.xml +0 -19
  237. data/test/resources/voresource/resource_v0_10.xml +0 -19
  238. data/test/resources/voresource/resource_v1_0.xml +0 -79
  239. data/test/resources/voresource/service_resource_v1_0.xml +0 -91
  240. data/test/resources/voresource/unittest_v0_10.rb +0 -61
  241. data/test/resources/voresource/unittest_v0_9.rb +0 -4
  242. data/test/resources/voresource/unittest_v1_0.rb +0 -190
  243. data/test/services/gestalt/unittest.rb +0 -74
  244. data/test/services/registry/unittest.rb +0 -34
  245. data/test/services/resolver/unittest.rb +0 -38
  246. data/test/simple/unittest.rb +0 -46
  247. data/test/spacetime/unittest.rb +0 -39
  248. data/test/stc/catalog_entry_location_v1_20.xml +0 -112
  249. data/test/stc/obs_data_location_v1_20.xml +0 -108
  250. data/test/stc/search_location_v1_20.xml +0 -54
  251. data/test/stc/stc_resource_profile_v1_20.xml +0 -60
  252. data/test/stc/unittest_v1_20.rb +0 -620
  253. data/test/voevent/unittest_v1_0.rb +0 -79
  254. data/test/voevent/unittest_v1_1.rb +0 -70
  255. data/test/voevent/voevent_v1_0.xml +0 -96
  256. data/test/votables/test.vot +0 -366
  257. data/test/votables/unittest.rb +0 -54
@@ -1,3 +0,0 @@
1
- require 'voruby/loader'
2
-
3
- require 'matrix'
@@ -1,607 +0,0 @@
1
- require 'voruby/spacetime/loader'
2
-
3
- module VORuby
4
-
5
- module SpaceTime
6
-
7
- class SpatialPosition
8
- attr_accessor :axis1, :axis2, :axis3
9
-
10
- def initialize(x, y, z)
11
- self.axis1 = x
12
- self.axis2 = y
13
- self.axis3 = z
14
- end
15
- end
16
- class TemporalPosition
17
- attr_accessor :time
18
-
19
- def initialize(t)
20
- self.time = t
21
- end
22
- end
23
-
24
- class Event
25
- attr_accessor :spatial_position, :temporal_position
26
-
27
- # Create a space-time even with the given spatial and temporal parts.
28
- def initialize(spatial, temporal)
29
- raise Exception::NotASpatialPosition.new(spatial) if !spatial.is_a?(SpatialPosition)
30
- raise Exception::NotATemporalPosition.new(temporal) if !temporal.is_a?(TemporalPosition)
31
-
32
- self.spatial_position = spatial
33
- self.temporal_position = temporal
34
- end
35
-
36
- def to_s
37
- "#{self.spatial_position}, #{self.temporal_position}"
38
- end
39
- end
40
-
41
- module Exception
42
- class NotASpatialPosition < RuntimeError
43
- def initialize(value)
44
- super("#{value} is not a SpatialPosition")
45
- end
46
- end
47
-
48
- class NotATemporalPosition < RuntimeError
49
- def initialize(value)
50
- super("#{value} is not a TemporalPosition")
51
- end
52
- end
53
- end
54
-
55
- end
56
-
57
- module CoordinateSystems
58
-
59
- class CoordinateOutOfRangeException < RuntimeError
60
- def initialize(coord_name, value, start_range, end_range)
61
- super("#{coord_name} of #{value} out of allowed range. Must be between #{start_range} and #{end_range}.")
62
- end
63
- end
64
-
65
- class NotACoordinateException < RuntimeError
66
- def initialize(value, intended_name)
67
- super("'#{value}' (#{value.class}) is not (or can't be converted to) a #{intended_name} object.")
68
- end
69
- end
70
-
71
- class NotATimeException < NotACoordinateException
72
- def initialize(value)
73
- super(value, 'Time')
74
- end
75
- end
76
-
77
- class InvalidTimeOffsetException < RuntimeError
78
- def initialize(value)
79
- super("Offset '#{value}' not recognized. Try a number with s, m, h or d appended.")
80
- end
81
- end
82
-
83
- class StandardTime < SpaceTime::TemporalPosition
84
- attr_reader :value
85
-
86
- # Create a StandardTime object from Ruby's core Time object.
87
- def initialize(time)
88
- self.value = time
89
-
90
- super(self.value)
91
- end
92
-
93
- def value=(time)
94
- raise NotATimeException.new(time) if !time.is_a?(Time)
95
- @value = time
96
- end
97
-
98
- # Returns an ISO 8601 compliant string representing the UTC time.
99
- def to_utc_s
100
- self.value.getutc.strftime("%Y-%m-%dT%H:%M:%SZ")
101
- end
102
-
103
- # Returns an ISO 8601 compliant string representing the local time.
104
- def to_local_s
105
- utc_offset_hrs = self.value.getlocal.utc_offset / (60.0 * 60.0)
106
- utc_offset_min = ((utc_offset_hrs - utc_offset_hrs.floor) * 60.0).to_i
107
- utc_offset = sprintf("%+03d:%02d", utc_offset_hrs.floor, utc_offset_min)
108
-
109
- self.value.getlocal.strftime("%Y-%m-%dT%H:%M:%S#{utc_offset}")
110
- end
111
-
112
- def extract_time(time_s)
113
- matches = time_s.match(/^(\d+(\.\d+)?)([smhd])?$/)
114
- raise InvalidTimeOffsetException.new(time_s) if !matches
115
-
116
- return calculate_time(matches[1].to_f, matches[3])
117
- end
118
-
119
- def calculate_time(value, unit)
120
- case unit
121
- when 's' then return value
122
- when 'm' then return value * 60.0
123
- when 'h' then return value * 60.0 * 60.0
124
- when 'd' then return value * 24.0 * 60.0 * 60.0
125
- else return value
126
- end
127
- end
128
-
129
- # Returns a StandardTime object projected forward the specified
130
- # amount of time. Input maybe be:
131
- # 1) a decimal number of seconds
132
- # 2) a string with a decimal number followed by a modifier specifying the unit.
133
- # The unit may be s = seconds, m = minutes, h = hours, d = days
134
- # i.e. 12.3h for 12.3 hours
135
- def +(time_s)
136
- new_time = nil
137
- (time_s.kind_of?(Numeric))? new_time = self.value + time_s: new_time = self.value + extract_time(time_s)
138
- return StandardTime.new(new_time)
139
- end
140
-
141
- # Add the specified number of seconds to the time.
142
- def increment(seconds)
143
- self.value = (self + seconds).value
144
- end
145
-
146
- # Returns a StandardTime object projected backward the specified
147
- # amount of time. Input maybe be:
148
- # 1) a decimal number of seconds
149
- # 2) a string with a decimal number followed by a modifier specifying the unit.
150
- # The unit may be s = seconds, m = minutes, h = hours, d = days
151
- # i.e. '12.3h' for 12.3 hours
152
- def -(time_s)
153
- new_time = nil
154
- (time_s.kind_of?(Numeric))? new_time = self.value + time_s: new_time = self.value - extract_time(time_s)
155
- return StandardTime.new(new_time)
156
- end
157
-
158
- # Subtract the specified number of seconds to the time.
159
- def decrement(seconds)
160
- self.value = (self - seconds).value
161
- end
162
-
163
- # Compare two StandardTimes.
164
- # if timeA before timeB, returns -1
165
- # if timeA == timeB, returns 0
166
- # if timeA after timeB, returns 1
167
- def <=>(time)
168
- self.value <=> time.value
169
- end
170
-
171
- def ==(time)
172
- self.value.eql?(time.value)
173
- end
174
-
175
- def to_s
176
- self.to_utc_s
177
- end
178
-
179
- private :extract_time, :calculate_time
180
- end
181
-
182
- module Equatorial
183
-
184
- module Exception
185
- class RAOutOfRange < CoordinateOutOfRangeException
186
- def initialize(value)
187
- super("Right ascension", value, 0, 360)
188
- end
189
- end
190
-
191
- class DecOutOfRange < CoordinateOutOfRangeException
192
- def initialize(value)
193
- super("Declination", value, -90, 90)
194
- end
195
- end
196
-
197
- class InvalidSexigesimalFormat < RuntimeError
198
- def initialize(value)
199
- super("Sexigesimal value of #{value} in a format that is not understood. Try NN:NN:NN.NN.")
200
- end
201
- end
202
-
203
- class NotARightAscension < NotACoordinateException
204
- def initialize(value)
205
- super(value, 'RightAscension')
206
- end
207
- end
208
-
209
- class NotADeclination < NotACoordinateException
210
- def initialize(value)
211
- super(value, 'Declination')
212
- end
213
- end
214
- end
215
-
216
- # Returns true if the provided string looks like it's
217
- # in standard sexigesimal format.
218
- def self.looks_like_sexigesimal?(sexig, sep='(:|(\s)+)')
219
- return true if sexig.match(/^[+-]?\d+#{sep}\d+#{sep}\d+/)
220
- return false
221
- end
222
-
223
- # Returns true if the provided string looks like it's
224
- # in standard decimal format.
225
- def self.looks_like_decimal?(decimal)
226
- return true if decimal.to_s.match(/^[+-]?\d+(\.\d*)?$/)
227
- return false
228
- end
229
-
230
- # Default is to J2000.0 (i.e. equinox2=2000.0, system=:fk5)
231
- def self.precession_matrix(equinox1, equinox2=2000.0, system=:fk5)
232
- a, b, c = (system == :fk4)? Equatorial::fk4_rotation_angles(equinox1, equinox2): Equatorial::fk5_rotation_angles(equinox1, equinox2)
233
-
234
- sina = Math.sin(a)
235
- sinb = Math.sin(b)
236
- sinc = Math.sin(c)
237
-
238
- cosa = Math.cos(a)
239
- cosb = Math.cos(b)
240
- cosc = Math.cos(c)
241
-
242
- Matrix.rows([
243
- [cosa*cosb*cosc-sina*sinb, sina*cosb+cosa*sinb*cosc, cosa*sinc],
244
- [-cosa*sinb-sina*cosb*cosc, cosa*cosb-sina*sinb*cosc, -sina*sinc],
245
- [-cosb*sinc, -sinb*sinc, cosc]
246
- ])
247
- end
248
-
249
- def self.fk5_rotation_angles(equinox1, equinox2=2000.0)
250
- deg_to_rad = Math::PI / 180.0
251
- sec_to_rad = deg_to_rad / 3600.0
252
- t = 0.001 * (equinox2 - equinox1)
253
- st = 0.001 * (equinox1 - 2000.0)
254
-
255
- a = sec_to_rad * t *
256
- (23062.181 +
257
- st * (139.656 + 0.0139 * st) +
258
- t * (30.188 - 0.344 * st + 17.998))
259
- b = sec_to_rad * t * t * (79.280 + 0.410 * st + 0.205 * t) + a
260
- c = sec_to_rad * t *
261
- (20043.109 -
262
- st * (85.33 + 0.217 * st) +
263
- t * (-42.665 - 0.217 * st - 41.833 * t))
264
-
265
- return [a, b, c]
266
- end
267
-
268
- def self.fk4_rotation_angles(equinox1, equinox2=2000.0)
269
- deg_to_rad = Math::PI / 180.0
270
- sec_to_rad = deg_to_rad / 3600.0
271
- t = 0.001 * (equinox2 - equinox1)
272
- st = 0.001 * (equinox1 - 1900.0)
273
-
274
- a = sec_to_rad * t *
275
- (23042.53 +
276
- st * (139.75 + 0.06 * st) +
277
- t * (30.23 - 0.27 * st + 18.0 * t))
278
- b = sec_to_rad * t * t * (79.27 + 0.66 * st + 0.32 * t) + a
279
- c = sec_to_rad * t *
280
- (20046.85 -
281
- st * (85.33 + 0.37 * st) +
282
- t * (-42.67 - 0.37 * st - 41.8 * t))
283
-
284
- return [a, b, c]
285
- end
286
-
287
- class RightAscension
288
- attr_reader :value
289
-
290
- MIN_ALLOWED_VALUE = 0.0
291
- MAX_ALLOWED_VALUE = 360.0
292
-
293
- # Create a RightAscenson object.
294
- def initialize(ra)
295
- self.value = ra
296
- end
297
-
298
- def value=(ra)
299
- if ra.is_a?(Numeric) or Equatorial::looks_like_decimal?(ra)
300
- @value = ra.to_f
301
- elsif ra.is_a?(String)
302
- if Equatorial::looks_like_sexigesimal?(ra)
303
- @value = RightAscension.from_sexigesimal(ra).value
304
- else
305
- raise Exception::InvalidSexigesimalFormat.new(ra)
306
- end
307
- else
308
- raise Exception::NotARightAscension.new(ra)
309
- end
310
-
311
- raise Exception::RAOutOfRange.new(ra) if !RightAscension::in_range?(@value)
312
- end
313
-
314
- # Is the supplied number in the correct range for a right ascension
315
- # (i.e between 0 and 360 degrees)?
316
- def self.in_range?(ra)
317
- (MIN_ALLOWED_VALUE..MAX_ALLOWED_VALUE) === ra
318
- end
319
-
320
- # Create a RightAscension object from a string in sexigesimal format.
321
- # Numerical values may be separated by a space or colon (but not both).
322
- def self.from_sexigesimal(ra)
323
- raise Exception::InvalidSexigesimalFormat.new(ra) if !Equatorial::looks_like_sexigesimal?(ra)
324
-
325
- hours_s, minutes_s, seconds_s = ra.split(/:|\s+/)
326
-
327
- hours = hours_s.to_f
328
- minutes = minutes_s.to_f
329
- seconds = seconds_s.to_f
330
-
331
- ra_degrees = 15.0 * (hours + (minutes + seconds.to_f / 60.0) / 60.0)
332
- return RightAscension.new(ra_degrees)
333
- end
334
-
335
- # Return the value of the ra as a string in sexigesimal format.
336
- def to_sexigesimal(sep=':')
337
- rah = (self.value / 15.0).to_i()
338
- ram = ((self.value - 15.0 * rah) * (60.0 / 15.0)).to_i()
339
- ras = self.value - (rah * 15.0) - (ram / (60.0 / 15.0))
340
- ras = ras * (60.0 * 60.0 / 15.0)
341
-
342
- return sprintf("%02u#{sep}%02u#{sep}%0.2f", rah, ram, ras)
343
- end
344
-
345
- # Returns a RightAscension object projected forward the specified
346
- # number of degrees.
347
- def +(degrees)
348
- new_degrees = self.value + degrees
349
- new_degrees = new_degrees - MAX_ALLOWED_VALUE if new_degrees > MAX_ALLOWED_VALUE
350
-
351
- RightAscension.new(new_degrees)
352
- end
353
-
354
- # Add the specified number of degrees to the ra.
355
- def increment(degrees)
356
- new_degrees = self + degrees
357
- self.value = new_degrees.value
358
- end
359
-
360
- # Returns a RightAscension object projected backward the specified
361
- # number of degrees.
362
- def -(degrees)
363
- new_degrees = self.value - degrees
364
- new_degrees = MAX_ALLOWED_VALUE + new_degrees if new_degrees < MIN_ALLOWED_VALUE
365
-
366
- RightAscension.new(new_degrees)
367
- end
368
-
369
- # Subtract the specified number of degrees from the ra.
370
- def decrement(degrees)
371
- new_degrees = self - degrees
372
- self.value = new_degrees.value
373
- end
374
-
375
- def <=>(ra)
376
- self.value <=> ra.value
377
- end
378
-
379
- def ==(ra)
380
- self.value == ra.value
381
- end
382
-
383
- def to_s
384
- "#{self.to_sexigesimal}"
385
- end
386
- end
387
-
388
- class Declination
389
- attr_reader :value
390
-
391
- MIN_ALLOWED_VALUE = -90.0
392
- MAX_ALLOWED_VALUE = 90.0
393
-
394
- # Create a Declination object from a decimal number.
395
- def initialize(dec)
396
- self.value = dec
397
- end
398
-
399
- def value=(dec)
400
- if dec.is_a?(Numeric) or Equatorial::looks_like_decimal?(dec)
401
- @value = dec.to_f
402
- elsif dec.is_a?(String)
403
- if Equatorial::looks_like_sexigesimal?(dec)
404
- @value = Declination.from_sexigesimal(dec).value
405
- else
406
- raise Exception::InvalidSexigesimalFormat.new(dec)
407
- end
408
- else
409
- raise Exception::NotADeclinationAscension.new(dec)
410
- end
411
-
412
- raise Exception::DecOutOfRange.new(dec) if !Declination::in_range?(@value)
413
- end
414
-
415
- # Is the supplied number in the correct range for a declination
416
- # (i.e between -90 and 90 degrees)?
417
- def self.in_range?(dec)
418
- (MIN_ALLOWED_VALUE..MAX_ALLOWED_VALUE) === dec
419
- end
420
-
421
- # Create a Declination object from a string in sexigesimal format.
422
- # Numerical values may be separated by a space or colon (but not both).
423
- def self.from_sexigesimal(dec)
424
- raise Exception::InvalidSexigesimalFormat.new(dec) if !Equatorial::looks_like_sexigesimal?(dec)
425
-
426
- degree, arcmin, arcsec = dec.split(/:|\s+/)
427
- degree_f = degree.to_f()
428
- arcmin_f = (arcmin.to_f() / 60.0)
429
- arcsec_f = (arcsec.to_f() / (60.0 * 60.0))
430
-
431
- return Declination.new(degree_f - arcmin_f - arcsec_f) if degree_f < 0
432
- return Declination.new(degree_f + arcmin_f + arcsec_f)
433
- end
434
-
435
- # Return the value of the dec as a string in sexigesimal format.
436
- def to_sexigesimal(sep=':')
437
- degrees = self.value
438
- decsign = '+'
439
- if degrees < 0
440
- decsign = '-'
441
- degrees = -degrees
442
- end
443
- decd = degrees.to_i()
444
- decm = ((degrees - decd) * 60.0).to_i()
445
- decs = degrees - decd - (decm / 60.0)
446
- decs = decs * 60.0 * 60.0
447
-
448
- return sprintf("%s%02u#{sep}%02u#{sep}%0.2f", decsign, decd, decm, decs)
449
- end
450
-
451
- # Returns a declination object projected forward the specified
452
- # number of degrees. Note that if the new object will have a
453
- # value greater than 90 degrees, the declination will be assumed
454
- # to be exactly 90 degrees, and similarly for -90 degrees.
455
- def +(degrees)
456
- new_degrees = self.value + degrees
457
- new_degrees = MAX_ALLOWED_VALUE if new_degrees > MAX_ALLOWED_VALUE
458
- new_degrees = MIN_ALLOWED_VALUE if new_degrees < MIN_ALLOWED_VALUE
459
-
460
- Declination.new(new_degrees)
461
- end
462
-
463
- # Add the specified number of degrees to the dec.
464
- def increment(degrees)
465
- new_degrees = self + degrees
466
- self.value = new_degrees.value
467
- end
468
-
469
- # Returns a declination object projected backwards the specified
470
- # number of degrees. Note that if the new object will have a
471
- # value greater less than -90 degrees, the declination will be assumed
472
- # to be exactly -90 degrees.
473
- def -(degrees)
474
- new_degrees = self.value - degrees
475
- new_degrees = MIN_ALLOWED_VALUE if new_degrees < MIN_ALLOWED_VALUE
476
-
477
- Declination.new(new_degrees)
478
- end
479
-
480
- # Subtract the specified number of degrees from the dec.
481
- def decrement(degrees)
482
- new_degrees = self - degrees
483
- self.value = new_degrees.value
484
- end
485
-
486
- def <=>(dec)
487
- self.value <=> dec.value
488
- end
489
-
490
- def ==(dec)
491
- self.value == dec.value
492
- end
493
-
494
- def to_s
495
- "#{self.to_sexigesimal}"
496
- end
497
- end
498
-
499
- class RADecPosition < SpaceTime::SpatialPosition
500
- attr_reader :ra, :dec, :distance
501
- attr_accessor :equinox, :system
502
-
503
- # Create a Position object. ra and dec may be:
504
- # 1) RightAscension or Declination objects
505
- # 2) Sexigesimal strings in standard format
506
- # 3) Strings that looks like decimals
507
- # 4) Degrees in decimal format.
508
- def initialize(ra, dec, distance=nil, equinox=2000.0, system=:fk5)
509
- self.ra = ra
510
- self.dec = dec
511
- self.distance = distance
512
- self.equinox = equinox
513
- self.system = system
514
-
515
- super(self.ra, self.dec, self.distance)
516
- end
517
-
518
- def ra=(ra)
519
- (ra.is_a?(RightAscension))? @ra = ra: @ra = RightAscension.new(ra)
520
- end
521
-
522
- def dec=(dec)
523
- (dec.is_a?(Declination))? @dec = dec: @dec = Declination.new(dec)
524
- end
525
-
526
- def distance=(dist)
527
- @distance = dist
528
- end
529
-
530
- # Returns the angular separation between two positions in degrees.
531
- def angular_separation(position)
532
- # Convert to radians
533
- ra1 = self.ra.value * (Math::PI / 180.0)
534
- dec1 = self.dec.value * (Math::PI / 180.0)
535
- ra2 = position.ra.value * (Math::PI / 180.0)
536
- dec2 = position.dec.value * (Math::PI / 180.0)
537
-
538
- ninety = 90.0 * (Math::PI / 180) # One quarter of a circle (90 degrees) in radians
539
-
540
- sep = Math.acos(
541
- Math.cos(ninety - dec1) * Math.cos(ninety - dec2) +
542
- Math.sin(ninety - dec1) * Math.sin(ninety - dec2) * Math.cos(ra1 - ra2)
543
- )
544
-
545
- return sep * (180.0 / Math::PI)
546
- end
547
-
548
- def ==(position)
549
- # Precess the new position object into the same equinox as the receiver.
550
- position = position.precess(self.equinox, self.system) if position.equinox != self.equinox and position.system != self.system
551
- self.ra == position.ra && self.dec == position.dec && self.distance == position.distance
552
- end
553
-
554
- # Precess the position to the specified equinox.
555
- # The constants for the precession matrix and general algorithm are taken from the IDL astro routines PREMAT and PRECESS.
556
- # Notes: Accuracy of precession decreases for declination values near 90 degrees.
557
- # Should not be used more than 2.5 centuries from 2000 on the FK5 system (1950.0 on the FK4 system).
558
- def precess(to_equinox=2000.0, system=:fk5)
559
- if self.equinox != to_equinox or self.system != system
560
- deg_to_rad = Math::PI / 180.0
561
-
562
- from_components = Matrix.row_vector(RADecPosition::equatorial_to_rectangular(self.ra.value, self.dec.value))
563
- precession_matrix = Equatorial::precession_matrix(self.equinox, to_equinox, system)
564
- to_components = from_components * precession_matrix
565
- ra, dec = RADecPosition::rectangular_to_equatorial(to_components[0, 0], to_components[0, 1], to_components[0, 2])
566
-
567
- return RADecPosition.new(ra, dec, self.distance, to_equinox, system)
568
- else
569
- return self
570
- end
571
- end
572
-
573
- def to_s
574
- coords = "#{self.ra}, #{self.dec}"
575
- coords << ", #{self.distance}" if self.distance
576
-
577
- coords
578
- end
579
-
580
- # Convert RA and Dec in decimal degrees to rectangular coordinates.
581
- def self.equatorial_to_rectangular(ra, dec)
582
- deg_to_rad = Math::PI / 180.0
583
-
584
- x = Math.cos(ra * deg_to_rad) * Math.cos(dec * deg_to_rad)
585
- y = Math.sin(ra * deg_to_rad) * Math.cos(dec * deg_to_rad)
586
- z = Math.sin(dec * deg_to_rad)
587
-
588
- return [x, y, z]
589
- end
590
-
591
- # Convert rectangular coordinates to equatorial coordinates in degrees.
592
- def self.rectangular_to_equatorial(x, y, z)
593
- rad_to_deg = 180.0 / Math::PI
594
-
595
- ra_rad = Math.atan(y/x)
596
- dec_rad = Math.asin(z)
597
-
598
- ra_rad = ra_rad + 2 * Math::PI if ra_rad < 0.0
599
-
600
- [ra_rad * rad_to_deg, dec_rad * rad_to_deg]
601
- end
602
- end
603
- end
604
-
605
- end
606
- end
607
-