voruby 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3271 @@
1
+ require 'voruby/stc/support'
2
+ require 'voruby/stc/1.10/region'
3
+ include VORuby::STC::V1_10::Region
4
+
5
+ module VORuby
6
+ module STC
7
+ module V1_10
8
+ module STC
9
+ include XMLUtilities
10
+
11
+ # A CoordFrame has to have at least a name
12
+ class CoordFrameType
13
+ include SerializableToXml
14
+
15
+ attr_reader :name
16
+
17
+ def initialize(options={})
18
+ options.each { |key, value| send("#{key}=", value) }
19
+ end
20
+
21
+ def name=(n)
22
+ @name = n ? n.to_s : nil
23
+ end
24
+
25
+ def to_xml(name=nil)
26
+ el = element(name)
27
+
28
+ if self.name
29
+ name = REXML::Element.new("#{obj_ns.prefix}:Name")
30
+ name.text = self.name
31
+ el.add_element(name)
32
+ end
33
+
34
+ el
35
+ end
36
+
37
+ def ==(f)
38
+ self.name == f.name
39
+ end
40
+ end
41
+
42
+ # CoordFrame substitution group head element
43
+ module CoordFrame
44
+ include SerializableToXml
45
+ end
46
+
47
+ class CoordFrameList < TypedArray
48
+ def self.restricted_to; [CoordFrame] end
49
+ def self.minimum_length; 1 end
50
+ end
51
+
52
+ # Head element (not abstract) of the CoordSys group
53
+ module CoordSys; end
54
+
55
+ # Coordinate equinox: B{year} or J{year} with at least one decimal; do not use in conjunction with ICRS
56
+ class CoordEquinox
57
+ attr_reader :value
58
+
59
+ def initialize(equinox)
60
+ self.value = equinox
61
+ end
62
+
63
+ def value=(e)
64
+ raise ArgumentError, "equinox '#{e}' in wrong format" if !e.match(/^[BJ]\-?\d?\d?\d?\d\d\d\d\.\d\d?\d?$/)
65
+ @value = e
66
+ end
67
+
68
+ def to_s
69
+ self.value.to_s
70
+ end
71
+
72
+ def ==(c)
73
+ self.value == c.value
74
+ end
75
+ end
76
+
77
+ # Abstract space reference frame type
78
+ class SpaceRefFrameType
79
+ def ==(f)
80
+ self.class == f.class
81
+ end
82
+ end
83
+
84
+ # Head element for the Coordinate reference frame substitution group: optional equinox
85
+ # with either a standard reference system (ICRS, FK5, FK4) and optional standard pole
86
+ # (equatorial, ecliptic, galactic, etc.), or a custom frame with pole (positive Z-axis)
87
+ # and positive X-axis direction
88
+ module SpaceRefFrame; end
89
+
90
+ # ICRS type
91
+ class IcrsType < SpaceRefFrameType
92
+ include SerializableToXml
93
+
94
+ def to_xml(name=nil)
95
+ element(name)
96
+ end
97
+
98
+ def self.from_xml(xml)
99
+ self.new
100
+ end
101
+ end
102
+
103
+ # FK[45] type
104
+ class FkType < SpaceRefFrameType
105
+ include SerializableToXml
106
+
107
+ attr_reader :equinox
108
+
109
+ def initialize(equinox)
110
+ self.equinox = equinox
111
+ end
112
+
113
+ def equinox=(e)
114
+ e = CoordEquinox.new(e.to_s) if !e.is_a?(CoordEquinox)
115
+ @equinox = e
116
+ end
117
+
118
+ def to_xml(name=nil)
119
+ el = element(name)
120
+
121
+ equinox = REXML::Element.new("#{obj_ns.prefix}:Equinox")
122
+ equinox.text = self.equinox.to_s
123
+ el.add_element(equinox)
124
+
125
+ el
126
+ end
127
+
128
+ def self.from_xml(xml)
129
+ root = element_from(xml)
130
+
131
+ self.new(
132
+ CoordEquinox.new(
133
+ REXML::XPath.first(root, 'x:Equinox', {'x' => obj_ns.uri}).text
134
+ )
135
+ )
136
+ end
137
+
138
+ def ==(f)
139
+ super(f) and
140
+ self.equinox == f.equinox
141
+ end
142
+ end
143
+
144
+ # A custome space reference frame type
145
+ # Define coordinate reference frame from scratch; pole and X-axis need to be defined in a known coordinate system
146
+ class CustomSpaceRefFrameType < SpaceRefFrameType
147
+ include SerializableToXml
148
+
149
+ attr_reader :frame, :pole_zaxis, :xaxis
150
+
151
+ def initialize(options={})
152
+ raise_argument_required_error('frame') if !options.has_key?(:frame)
153
+ raise_argument_required_error('pole z axis') if !options.has_key?(:pole_zaxis)
154
+ raise_argument_required_error('x axis') if !options.has_key?(:xaxis)
155
+ options.each { |key, value| send("#{key}=", value) }
156
+ end
157
+
158
+ def frame=(f)
159
+ raise_argument_required_error('frame') if !f
160
+ @frame = f.to_s
161
+ end
162
+
163
+ def pole_zaxis=(p)
164
+ raise_argument_required_error('pole z axis') if !p
165
+ raise_type_mismatch_error(p, AstroCoordsType)
166
+ @pole_zaxis = p
167
+ end
168
+
169
+ def xaxis=(x)
170
+ raise_argument_required_error('x axis') if !x
171
+ raise_type_mismatch_error(x, AstroCoordsType)
172
+ @xaxis = x
173
+ end
174
+
175
+ def ==(f)
176
+ super(f) and
177
+ self.frame == f.frame and
178
+ self.pole_zaxis == f.pole_zaxis and
179
+ self.xaxis == f.xaxis
180
+ end
181
+
182
+ def to_xml(name=nil)
183
+ el = element(name)
184
+
185
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
186
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
187
+
188
+ frame = REXML::Element.new("#{obj_ns.prefix}:Frame")
189
+ frame.text = self.frame
190
+ el.add_element(frame)
191
+
192
+ el.add_element(self.pole_zaxis.to_xml('Pole_Zaxis', obj_ns))
193
+ el.add_element(self.xaxis.to_xml('Xaxis', obj_ns))
194
+
195
+ collapse_namespaces(el)
196
+
197
+ el
198
+ end
199
+
200
+ def self.from_xml(xml)
201
+ root = element_from(xml)
202
+
203
+ options = {
204
+ :frame => REXML::XPath.first(root, 'x:Frame', {'x' => obj_ns.uri}).text,
205
+ :pole_zaxis => AstroCoords.from_xml(REXML::XPath.first(root, 'x:Pole_Zaxis', {'x' => obj_ns.uri})),
206
+ :xaxis => AstroCoords.from_xml(REXML::XPath.first(root, 'x:Xaxis', {'x' => obj_ns.uri}))
207
+ }
208
+
209
+ CustomSpaceRefFrameType.new(options)
210
+ end
211
+ end
212
+
213
+ # The ICRS reference frame
214
+ class Icrs < IcrsType
215
+ include SpaceRefFrame
216
+
217
+ def self.element_name; 'ICRS' end
218
+
219
+ def to_xml
220
+ super('ICRS')
221
+ end
222
+ end
223
+
224
+ # FK4; needs a Besselian epoch
225
+ class Fk4 < FkType
226
+ include SpaceRefFrame
227
+
228
+ def self.element_name; 'FK4' end
229
+
230
+ def to_xml
231
+ super('FK4')
232
+ end
233
+ end
234
+
235
+ # FK5; needs a Julian epoch
236
+ class Fk5 < FkType
237
+ include SpaceRefFrame
238
+
239
+ def self.element_name; 'FK5' end
240
+
241
+ def to_xml
242
+ super('FK5')
243
+ end
244
+ end
245
+
246
+ # Ecliptic coorindates; needs an epoch
247
+ class Ecliptic < FkType
248
+ include SpaceRefFrame
249
+
250
+ def self.element_name; 'ECLIPTIC' end
251
+
252
+ def to_xml
253
+ super('ECLIPTIC')
254
+ end
255
+ end
256
+
257
+ # Galactic coordinates; first system
258
+ class GalacticI < IcrsType
259
+ include SpaceRefFrame
260
+
261
+ def self.element_name; 'GALACTIC_I' end
262
+
263
+ def to_xml
264
+ super('GALACTIC_I')
265
+ end
266
+ end
267
+
268
+ # Galactic coordinates; second system
269
+ class GalacticII < IcrsType
270
+ include SpaceRefFrame
271
+
272
+ def self.element_name; 'GALACTIC_II' end
273
+
274
+ def to_xml
275
+ super('GALACTIC_II')
276
+ end
277
+ end
278
+
279
+ # SuperGalactic coordinates
280
+ class SuperGalactic < IcrsType
281
+ include SpaceRefFrame
282
+
283
+ def self.element_name; 'SUPER_GALACTIC' end
284
+
285
+ def to_xml
286
+ super('SUPER_GALACTIC')
287
+ end
288
+ end
289
+
290
+ # Local Azimuth and Elevation coordinates
291
+ class AzEl < IcrsType
292
+ include SpaceRefFrame
293
+
294
+ def self.element_name; 'AZ_EL' end
295
+
296
+ def to_xml
297
+ super('AZ_EL')
298
+ end
299
+ end
300
+
301
+ # Generic Body coordinates
302
+ class Body < IcrsType
303
+ include SpaceRefFrame
304
+
305
+ def self.element_name; 'BODY' end
306
+
307
+ def to_xml
308
+ super('BODY')
309
+ end
310
+ end
311
+
312
+ # The geographic reference frame
313
+ class Geo < IcrsType
314
+ include SpaceRefFrame
315
+
316
+ def self.element_name; 'GEO' end
317
+
318
+ def to_xml
319
+ super('GEO')
320
+ end
321
+ end
322
+
323
+ # The geodetic reference frame
324
+ class Geod < IcrsType
325
+ include SpaceRefFrame
326
+
327
+ def self.element_name; 'GEOD' end
328
+
329
+ def to_xml
330
+ super('GEOD')
331
+ end
332
+ end
333
+
334
+ # The geomagnetic reference frame
335
+ class Mag < IcrsType
336
+ include SpaceRefFrame
337
+
338
+ def self.element_name; 'MAG' end
339
+
340
+ def to_xml
341
+ super('MAG')
342
+ end
343
+ end
344
+
345
+ # the geocentric solar ecliptic reference frame
346
+ class Gse < IcrsType
347
+ include SpaceRefFrame
348
+
349
+ def self.element_name; 'GSE' end
350
+
351
+ def to_xml
352
+ super('GSE')
353
+ end
354
+ end
355
+
356
+ # The geocentric solar magnetic reference frame
357
+ class Gsm < IcrsType
358
+ include SpaceRefFrame
359
+
360
+ def self.element_name; 'GSM' end
361
+
362
+ def to_xml
363
+ super('GSM')
364
+ end
365
+ end
366
+
367
+ # The solar magnetic reference frame
368
+ class Sm < IcrsType
369
+ include SpaceRefFrame
370
+
371
+ def self.element_name; 'SM' end
372
+
373
+ def to_xml
374
+ super('SM')
375
+ end
376
+ end
377
+
378
+ # The heliographic reference frame
379
+ class Hgc < IcrsType
380
+ include SpaceRefFrame
381
+
382
+ def self.element_name; 'HGC' end
383
+
384
+ def to_xml
385
+ super('HGC')
386
+ end
387
+ end
388
+
389
+ # The heliocentric earth ecliptic reference frame
390
+ class Hee < IcrsType
391
+ include SpaceRefFrame
392
+
393
+ def self.element_name; 'HEE' end
394
+
395
+ def to_xml
396
+ super('HEE')
397
+ end
398
+ end
399
+
400
+ # The heliocentric earth equatorial reference frame
401
+ class Heeq < IcrsType
402
+ include SpaceRefFrame
403
+
404
+ def self.element_name; 'HEEQ' end
405
+
406
+ def to_xml
407
+ super('HEEQ')
408
+ end
409
+ end
410
+
411
+ # The heliocentric intertial reference frame
412
+ class Hci < IcrsType
413
+ include SpaceRefFrame
414
+
415
+ def self.element_name; 'HCI' end
416
+
417
+ def to_xml
418
+ super('HCI')
419
+ end
420
+ end
421
+
422
+ # The heliocentric of date reference frame
423
+ class Hcd < IcrsType
424
+ include SpaceRefFrame
425
+
426
+ def self.element_name; 'HCD' end
427
+
428
+ def to_xml
429
+ super('HCD')
430
+ end
431
+ end
432
+
433
+ # The planetocentric reference frame anchored on Mercury
434
+ class MercuryC < IcrsType
435
+ include SpaceRefFrame
436
+
437
+ def self.element_name; 'MERCURY_C' end
438
+
439
+ def to_xml
440
+ super('MERCURY_C')
441
+ end
442
+ end
443
+
444
+ # The planetocentric reference frame anchored on Venus
445
+ class VenusC < IcrsType
446
+ include SpaceRefFrame
447
+
448
+ def self.element_name; 'VENUS_C' end
449
+
450
+ def to_xml
451
+ super('VENUS_C')
452
+ end
453
+ end
454
+
455
+ # The lunacentric reference frame anchored on the moon
456
+ class LunaC < IcrsType
457
+ include SpaceRefFrame
458
+
459
+ def self.element_name; 'LUNA_C' end
460
+
461
+ def to_xml
462
+ super('LUNA_C')
463
+ end
464
+ end
465
+
466
+ # The planetocentric reference frame anchored on Mars
467
+ class MarsC < IcrsType
468
+ include SpaceRefFrame
469
+
470
+ def self.element_name; 'MARS_C' end
471
+
472
+ def to_xml
473
+ super('MARS_C')
474
+ end
475
+ end
476
+
477
+ # The planetocentric reference frame anchored on Jupiter
478
+ class JupiterCIII < IcrsType
479
+ include SpaceRefFrame
480
+
481
+ def self.element_name; 'JUPITER_C_III' end
482
+
483
+ def to_xml
484
+ super('JUPITER_C_III')
485
+ end
486
+ end
487
+
488
+ # The planetocentric reference frame anchored on Saturn
489
+ class SaturnCIII < IcrsType
490
+ include SpaceRefFrame
491
+
492
+ def self.element_name; 'SATURN_C_III' end
493
+
494
+ def to_xml
495
+ super('SATURN_C_III')
496
+ end
497
+ end
498
+
499
+ # The planetocentric reference frame anchored on Uranus
500
+ class UranusCIII < IcrsType
501
+ include SpaceRefFrame
502
+
503
+ def self.element_name; 'URANUS_C_III' end
504
+
505
+ def to_xml
506
+ super('URANUS_C_III')
507
+ end
508
+ end
509
+
510
+ # The planetocentric reference frame anchored on Neptune
511
+ class NeptuneCIII < IcrsType
512
+ include SpaceRefFrame
513
+
514
+ def self.element_name; 'NEPTUNE_C_III' end
515
+
516
+ def to_xml
517
+ super('NEPTUNE_C_III')
518
+ end
519
+ end
520
+
521
+ # The planetocentric reference frame anchored on Pluto
522
+ class PlutoC < IcrsType
523
+ include SpaceRefFrame
524
+
525
+ def self.element_name; 'PLUTO_C' end
526
+
527
+ def to_xml
528
+ super('PLUTO_C')
529
+ end
530
+ end
531
+
532
+ # The planetographic reference frame anchored on Mercury
533
+ class MercuryG < IcrsType
534
+ include SpaceRefFrame
535
+
536
+ def self.element_name; 'MERCURY_G' end
537
+
538
+ def to_xml
539
+ super('MERCURY_G')
540
+ end
541
+ end
542
+
543
+ # The planetographic reference frame anchored on Venus
544
+ class VenusG < IcrsType
545
+ include SpaceRefFrame
546
+
547
+ def self.element_name; 'VENUS_G' end
548
+
549
+ def to_xml
550
+ super('VENUS_G')
551
+ end
552
+ end
553
+
554
+ # The planetographic reference frame anchored on the moon
555
+ class LunaG < IcrsType
556
+ include SpaceRefFrame
557
+
558
+ def self.element_name; 'LUNA_G' end
559
+
560
+ def to_xml
561
+ super('LUNA_G')
562
+ end
563
+ end
564
+
565
+ # The planetographic reference frame anchored on Mars
566
+ class MarsG < IcrsType
567
+ include SpaceRefFrame
568
+
569
+ def self.element_name; 'MARS_G' end
570
+
571
+ def to_xml
572
+ super('MARS_G')
573
+ end
574
+ end
575
+
576
+ # The planetographic reference frame anchored on Jupiter
577
+ class JupiterGIII < IcrsType
578
+ include SpaceRefFrame
579
+
580
+ def self.element_name; 'JUPITER_G_III' end
581
+
582
+ def to_xml
583
+ super('JUPITER_G_III')
584
+ end
585
+ end
586
+
587
+ # The planetographic reference frame anchored on Saturn
588
+ class SaturnGIII < IcrsType
589
+ include SpaceRefFrame
590
+
591
+ def self.element_name; 'SATURN_G_III' end
592
+
593
+ def to_xml
594
+ super('SATURN_G_III')
595
+ end
596
+ end
597
+
598
+ # The planetographic reference frame anchored on Uranus
599
+ class UranusGIII < IcrsType
600
+ include SpaceRefFrame
601
+
602
+ def self.element_name; 'URANUS_G_III' end
603
+
604
+ def to_xml
605
+ super('URANUS_G_III')
606
+ end
607
+ end
608
+
609
+ # The planetographic reference frame anchored on Neptune
610
+ class NeptuneGIII < IcrsType
611
+ include SpaceRefFrame
612
+
613
+ def self.element_name; 'NEPTUNE_G_III' end
614
+
615
+ def to_xml
616
+ super('NEPTUNE_G_III')
617
+ end
618
+ end
619
+
620
+ # The planetographic reference frame anchored on Pluton
621
+ class PlutoG < IcrsType
622
+ include SpaceRefFrame
623
+
624
+ def self.element_name; 'PLUTO_G' end
625
+
626
+ def to_xml
627
+ super('PLUTO_G')
628
+ end
629
+ end
630
+
631
+ # Unknown space reference frame; the client is responsible for assigning a default
632
+ class UnknownFrame < IcrsType
633
+ include SpaceRefFrame
634
+
635
+ def self.element_name; 'UNKNOWNFRame' end
636
+
637
+ def to_xml
638
+ super('UNKNOWNFrame')
639
+ end
640
+ end
641
+
642
+ # Coordinate reference frame: a custom pole (positive Z-axis) and positive X-axis direction
643
+ class CustomSpaceRefFrame < CustomSpaceRefFrameType
644
+ include SpaceRefFrame
645
+
646
+ def self.element_name; 'CustomSpaceRefFrame' end
647
+
648
+ def to_xml
649
+ super('CustomSpaceRefFrame')
650
+ end
651
+
652
+ def self.from_xml(xml)
653
+ root = element_from(xml)
654
+
655
+ options = {
656
+ :frame => REXML::XPath.first(root, 'x:Frame', {'x' => obj_ns.uri}).text,
657
+ :pole_zaxis => AstroCoords.from_xml(REXML::XPath.first(root, 'x:Pole_Zaxis', {'x' => obj_ns.uri})),
658
+ :xaxis => AstroCoords.from_xml(REXML::XPath.first(root, 'x:Xaxis', {'x' => obj_ns.uri}))
659
+ }
660
+
661
+ CustomSpaceRefFrame.new(options)
662
+ end
663
+ end
664
+
665
+ # If solar system positions are implied anywhere, the planetary ephemeris to
666
+ # be used needs to be provided - usually JPL-DE405 with ICRS and JPL-DE200
667
+ # with FK5
668
+ class PlanetaryEphem < Enumeration
669
+ def self.choices; ['JPL-DE200', 'JPL-DE405'] end
670
+ end
671
+
672
+ # Abstract type for reference positions
673
+ class ReferencePositionType
674
+ include SerializableToXml
675
+ end
676
+
677
+ # Type for standard reference positions
678
+ class StdRefPos < ReferencePositionType
679
+ attr_reader :planetary_ephem
680
+
681
+ def initialize(ephem=nil)
682
+ self.planetary_ephem = ephem
683
+ end
684
+
685
+ def planetary_ephem=(e)
686
+ if e
687
+ e = PlanetaryEphem.new(e) if e.is_a?(String)
688
+ raise_type_mismatch_error(e, PlanetaryEphem)
689
+ end
690
+
691
+ @planetary_ephem = e
692
+ end
693
+
694
+ def to_xml(name=nil)
695
+ el = element(name)
696
+
697
+ if self.planetary_ephem
698
+ ephem = REXML::Element.new("#{obj_ns.prefix}:PlanetaryEphem")
699
+ ephem.text = self.planetary_ephem.to_s
700
+ el.add_element(ephem)
701
+ end
702
+
703
+ collapse_namespaces(el)
704
+ el
705
+ end
706
+
707
+ def self.from_xml(xml)
708
+ root = element_from(xml)
709
+
710
+ ephem_node = REXML::XPath.first(root, 'x:PlanetaryEphem', {'x' => obj_ns.uri})
711
+ ephem = ephem_node ? PlanetaryEphem.new(ephem_node.text) : nil
712
+
713
+ self.new(ephem)
714
+ end
715
+
716
+ def ==(p)
717
+ self.planetary_ephem == p.planetary_ephem
718
+ end
719
+ end
720
+
721
+ # Type for custom positions: specifies reference origin<
722
+ class CustomRefPosType < ReferencePositionType
723
+ attr_reader :coord_origin
724
+
725
+ def initialize(origin)
726
+ self.coord_origin = origin
727
+ end
728
+
729
+ def coord_origin=(c)
730
+ raise_argument_required_error('coordinate origin required') if !c
731
+ raise_type_mismatch_error(c, AstroCoordsType)
732
+ @coord_origin = c
733
+ end
734
+
735
+ def to_xml(name=nil)
736
+ el = element(name)
737
+
738
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
739
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
740
+
741
+ el.add_element(self.coord_origin.to_xml('CoordOrigin', obj_ns))
742
+
743
+ collapse_namespaces(el)
744
+ el
745
+ end
746
+
747
+ def self.from_xml(xml)
748
+ root = element_from(xml)
749
+ self.new(
750
+ AstroCoords.from_xml(REXML::XPath.first(root, 'x:CoordOrigin', {'x' => obj_ns.uri}))
751
+ )
752
+ end
753
+
754
+ def ==(p)
755
+ self.coord_origin == p.coord_origin
756
+ end
757
+ end
758
+
759
+ # Head element from the ReferencePosition substitution group: either a "known place"
760
+ # such as geocenter or barycenter (RefPos), or a position defined in a known coordinate
761
+ # system (CoordOrigin)
762
+ module ReferencePosition; end
763
+
764
+ # Location of the observer/telescope
765
+ class Topocenter < StdRefPos
766
+ include ReferencePosition
767
+
768
+ def self.element_name; 'TOPOCENTER' end
769
+
770
+ def to_xml
771
+ super('TOPOCENTER')
772
+ end
773
+ end
774
+
775
+ # Barycenter of the solar system
776
+ class Barycenter < StdRefPos
777
+ include ReferencePosition
778
+
779
+ def self.element_name; 'BARYCENTER' end
780
+
781
+ def to_xml
782
+ super('BARYCENTER')
783
+ end
784
+ end
785
+
786
+ # Center of the sun
787
+ class Heliocenter < StdRefPos
788
+ include ReferencePosition
789
+
790
+ def self.element_name; 'HELIOCENTER' end
791
+
792
+ def to_xml
793
+ super('HELIOCENTER')
794
+ end
795
+ end
796
+
797
+ # Center of the earth
798
+ class Geocenter < StdRefPos
799
+ include ReferencePosition
800
+
801
+ def self.element_name; 'GEOCENTER' end
802
+
803
+ def to_xml
804
+ super('GEOCENTER')
805
+ end
806
+ end
807
+
808
+ # Local standard of rest (only used form Doppler velocities)
809
+ class Lsr < StdRefPos
810
+ include ReferencePosition
811
+
812
+ def self.element_name; 'LSR' end
813
+
814
+ def to_xml
815
+ super('LSR')
816
+ end
817
+ end
818
+
819
+ # Center of the galaxy
820
+ class GalacticCenter < StdRefPos
821
+ include ReferencePosition
822
+
823
+ def self.element_name; 'GALACTIC_CENTER' end
824
+
825
+ def to_xml
826
+ super('GALACTIC_CENTER')
827
+ end
828
+ end
829
+
830
+ # Center of the local super cluster
831
+ class SuperGalacticCenter < StdRefPos
832
+ include ReferencePosition
833
+
834
+ def self.element_name; 'SUPER_GALACTIC_CENTER' end
835
+
836
+ def to_xml
837
+ super('SUPER_GALACTIC_CENTER')
838
+ end
839
+ end
840
+
841
+ # Center of the moon
842
+ class Moon < StdRefPos
843
+ include ReferencePosition
844
+
845
+ def self.element_name; 'MOON' end
846
+
847
+ def to_xml
848
+ super('MOON')
849
+ end
850
+ end
851
+
852
+ # Barycenter of the Earth-Moon system
853
+ class Embarycenter < StdRefPos
854
+ include ReferencePosition
855
+
856
+ def self.element_name; 'EMBARYCENTER' end
857
+
858
+ def to_xml
859
+ super('EMBARYCENTER')
860
+ end
861
+ end
862
+
863
+ # Center of Mercury
864
+ class Mercury < StdRefPos
865
+ include ReferencePosition
866
+
867
+ def self.element_name; 'MERCURY' end
868
+
869
+ def to_xml
870
+ super('MERCURY')
871
+ end
872
+ end
873
+
874
+ # Center of Venus
875
+ class Venus < StdRefPos
876
+ include ReferencePosition
877
+
878
+ def self.element_name; 'VENUS' end
879
+
880
+ def to_xml
881
+ super('VENUS')
882
+ end
883
+ end
884
+
885
+ # Center of Mars
886
+ class Mars < StdRefPos
887
+ include ReferencePosition
888
+
889
+ def self.element_name; 'MARS' end
890
+
891
+ def to_xml
892
+ super('MARS')
893
+ end
894
+ end
895
+
896
+ # Center of Jupiter
897
+ class Jupiter < StdRefPos
898
+ include ReferencePosition
899
+
900
+ def self.element_name; 'JUPITER' end
901
+
902
+ def to_xml
903
+ super('JUPITER')
904
+ end
905
+ end
906
+
907
+ # Center of Saturn
908
+ class Saturn < StdRefPos
909
+ include ReferencePosition
910
+
911
+ def self.element_name; 'SATURN' end
912
+
913
+ def to_xml
914
+ super('SATURN')
915
+ end
916
+ end
917
+
918
+ # Center of Uranus
919
+ class Uranus < StdRefPos
920
+ include ReferencePosition
921
+
922
+ def self.element_name; 'URANUS' end
923
+
924
+ def to_xml
925
+ super('URANUS')
926
+ end
927
+ end
928
+
929
+ # Center of Neptune
930
+ class Neptune < StdRefPos
931
+ include ReferencePosition
932
+
933
+ def self.element_name; 'NEPTUNE' end
934
+
935
+ def to_xml
936
+ super('NEPTUNE')
937
+ end
938
+ end
939
+
940
+ # Center of Pluto
941
+ class Pluto < StdRefPos
942
+ include ReferencePosition
943
+
944
+ def self.element_name; 'PLUTO' end
945
+
946
+ def to_xml
947
+ super('PLUTO')
948
+ end
949
+ end
950
+
951
+ # A relocatable origin, especially useful for simulations
952
+ class Relocatable < StdRefPos
953
+ include ReferencePosition
954
+
955
+ def self.element_name; 'RELOCATABLE' end
956
+
957
+ def to_xml
958
+ super('RELOCATABLE')
959
+ end
960
+ end
961
+
962
+ # Unknown origin; the client is responsible for assigning a default
963
+ class UnknownRefPos < StdRefPos
964
+ include ReferencePosition
965
+
966
+ def self.element_name; 'UNKNOWNRefPos' end
967
+
968
+ def to_xml
969
+ super('UNKNOWNRefPos')
970
+ end
971
+ end
972
+
973
+ # Origin of the coordinate system, given as a position in another, known, coordinate system
974
+ class CustomRefPos < CustomRefPosType
975
+ include ReferencePosition
976
+
977
+ def to_xml
978
+ super('CustomRefPos')
979
+ end
980
+ end
981
+
982
+ # Provides the coordinate definitions: number of axes, SPHERICAL, CARTESIAN, or UNITSPHERE,
983
+ # presence of velocities
984
+ class CoordFlavorType
985
+ include SerializableToXml
986
+
987
+ attr_reader :coord_vel
988
+
989
+ def initialize(naxes=2, vel=false)
990
+ self.coord_naxes = naxes
991
+ self.coord_vel = vel
992
+ end
993
+
994
+ def coord_naxes=(n)
995
+ n = Integer(n)
996
+ raise ArgumentError, 'number of axes must be between 1 and 3' if n and (n < 1 or n > 3)
997
+ @coord_naxes = n
998
+ end
999
+
1000
+ def coord_naxes
1001
+ @coord_naxes || 2
1002
+ end
1003
+
1004
+ def coord_vel=(v)
1005
+ @coord_vel = v ? true : false
1006
+ end
1007
+
1008
+ def coord_vel
1009
+ @coord_vel == nil ? false : @coord_vel
1010
+ end
1011
+
1012
+ def to_xml(name=nil)
1013
+ el = element(name)
1014
+ el.attributes["#{obj_ns.prefix}:coord_naxes"] = self.coord_naxes.to_s
1015
+ el.attributes["#{obj_ns.prefix}:coord_vel"] = self.coord_vel.to_s
1016
+ el
1017
+ end
1018
+
1019
+ def self.from_xml(xml)
1020
+ root = element_from(xml)
1021
+
1022
+ coord_naxes = root.attributes.get_attribute_ns(obj_ns.uri, 'coord_naxes')
1023
+ coord_vel = root.attributes.get_attribute_ns(obj_ns.uri, 'coord_vel')
1024
+
1025
+ self.new(
1026
+ coord_naxes ? Integer(coord_naxes.value) : nil,
1027
+ coord_vel ? (coord_vel.value == 'true' ? true : false) : nil
1028
+ )
1029
+ end
1030
+
1031
+ def ==(f)
1032
+ self.coord_naxes == f.coord_naxes and
1033
+ self.coord_vel == f.coord_vel
1034
+ end
1035
+ end
1036
+
1037
+ # Abstract head element for the CoordFlavor substitution group
1038
+ module CoordFlavor; end
1039
+
1040
+ # Spherical (2-D) coordinates
1041
+ class Spherical < CoordFlavorType
1042
+ include CoordFlavor
1043
+
1044
+ def self.element_name; 'SPHERICAL' end
1045
+
1046
+ def to_xml
1047
+ super('SPHERICAL')
1048
+ end
1049
+ end
1050
+
1051
+ # Cartesian 1-, 2-, or 3-D coordinates
1052
+ class Cartesian < CoordFlavorType
1053
+ include CoordFlavor
1054
+
1055
+ def self.element_name; 'CARTESIAN' end
1056
+
1057
+ def to_xml
1058
+ super('CARTESIAN')
1059
+ end
1060
+ end
1061
+
1062
+ # 3-D Unit sphere coordinates (direction cosines)
1063
+ class UnitSphere < CoordFlavorType
1064
+ include CoordFlavor
1065
+
1066
+ def self.element_name; 'UNITSPHERE' end
1067
+
1068
+ def to_xml
1069
+ super('UNITSPHERE')
1070
+ end
1071
+ end
1072
+
1073
+ # 3-D geographic-like spherical coordinates (longitude, latitude, altitude)
1074
+ class Geographic < CoordFlavorType
1075
+ include CoordFlavor
1076
+
1077
+ def self.element_name; 'GEOGRAPHIC' end
1078
+
1079
+ def to_xml
1080
+ super('GEOGRAPHIC')
1081
+ end
1082
+ end
1083
+
1084
+ # A spatial coordinate frame consists of a coordinate frame and a reference position
1085
+ class SpaceFrameType < CoordFrameType
1086
+ attr_reader :space_ref_frame, :reference_position, :offset_center, :coord_flavor
1087
+
1088
+ def initialize(options={})
1089
+ raise_argument_required_error('space reference frame') if !options.has_key?(:space_ref_frame)
1090
+ raise_argument_required_error('reference position') if !options.has_key?(:reference_position)
1091
+ raise_argument_required_error('coordinate flavor') if !options.has_key?(:coord_flavor)
1092
+ super(options)
1093
+ end
1094
+
1095
+ # Coordinate reference frame: optional equinox with either a standard reference system
1096
+ # (ICRS, FK5, FK4) and optional standard pole (equatorial, ecliptic, galactic, etc.),
1097
+ # or pole (positive Z-axis) and positive X-axis direction
1098
+ def space_ref_frame=(f)
1099
+ raise_argument_required_error('space reference frame') if !f
1100
+ raise_type_mismatch_error(f, SpaceRefFrame)
1101
+ @space_ref_frame = f
1102
+ end
1103
+
1104
+ # Origin of the coordinate reference frame: either a "known place" such as geocenter or barycenter,
1105
+ # or a position defined in a known coordinate system
1106
+ def reference_position=(p)
1107
+ raise_argument_required_error('reference position') if !p
1108
+ raise_type_mismatch_error(p, ReferencePosition)
1109
+ @reference_position = p
1110
+ end
1111
+
1112
+ def offset_center=(o)
1113
+ raise_type_mismatch_error(o, CoordValue)
1114
+ @offset_center = o
1115
+ end
1116
+
1117
+ # Provides the coordinate definitions: number of axes, SPHERICAL or CARTESIAN, presence of velocities,
1118
+ # and the Doppler definitions (if needed)
1119
+ def coord_flavor=(f)
1120
+ raise_argument_required_error('coordinate flavor') if !f
1121
+ raise_type_mismatch_error(f, CoordFlavor)
1122
+ @coord_flavor = f
1123
+ end
1124
+
1125
+ def ==(f)
1126
+ super(f) and
1127
+ self.space_ref_frame == f.space_ref_frame and
1128
+ self.reference_position == f.reference_position and
1129
+ self.offset_center == f.offset_center and
1130
+ self.coord_flavor == f.coord_flavor
1131
+ end
1132
+
1133
+ def to_xml(name=nil)
1134
+ el = super(name)
1135
+
1136
+ if self.offset_center
1137
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
1138
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
1139
+ end
1140
+
1141
+ el.add_element(self.space_ref_frame.to_xml)
1142
+ el.add_element(self.reference_position.to_xml)
1143
+
1144
+ if self.offset_center
1145
+ offset_center = REXML::Element.new("#{obj_ns.prefix}:OffsetCenter")
1146
+ offset_center.add_element(self.offset_center.to_xml)
1147
+ el.add_element(offset_center)
1148
+ end
1149
+
1150
+ el.add_element(self.coord_flavor.to_xml)
1151
+
1152
+ collapse_namespaces(el)
1153
+ el
1154
+ end
1155
+
1156
+ def self.from_xml(xml)
1157
+ root = element_from(xml)
1158
+
1159
+ options = {
1160
+ :space_ref_frame => xml_to_obj(root, SpaceRefFrame, true),
1161
+ :reference_position => xml_to_obj(root, ReferencePosition, true),
1162
+ :coord_flavor => xml_to_obj(root, CoordFlavor, true)
1163
+ }
1164
+
1165
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1166
+ options[:name] = name.text if name
1167
+
1168
+ offset_center = REXML::XPath.first(root, 'x:OffsetCenter', {'x' => obj_ns.uri})
1169
+ options[:offset_center] = xml_to_obj(offset_center, CoordValue, true, Coords) if offset_center
1170
+
1171
+ self.new(options)
1172
+ end
1173
+ end
1174
+
1175
+ # The spatial coordinate reference frame
1176
+ class SpaceFrame < SpaceFrameType
1177
+ include CoordFrame
1178
+ end
1179
+
1180
+ # The time reference frame consists of a timescale, a reference position, and optionally a reference
1181
+ # direction (needed when transformations have been applied)
1182
+ class TimeFrameType < CoordFrameType
1183
+ attr_reader :reference_position, :time_ref_direction
1184
+
1185
+ def initialize(options={})
1186
+ raise_argument_error('reference position') if !options.has_key?(:reference_position)
1187
+ super(options)
1188
+ end
1189
+
1190
+ # The time reference frame consists of a time scale, a time format, and a reference time, if needed
1191
+ def time_scale=(s)
1192
+ if s
1193
+ s = TimeScale.new(s) if s.is_a?(String)
1194
+ raise_type_mismatch_error(s, TimeScale)
1195
+ end
1196
+ @time_scale = s
1197
+ end
1198
+
1199
+ def time_scale
1200
+ @time_scale || TimeScale.new('TT')
1201
+ end
1202
+
1203
+ # Origin of the coordinate reference frame: either a "known place" such as geocenter or barycenter,
1204
+ # or a position defined in a known coordinate system
1205
+ def reference_position=(p)
1206
+ raise_argument_error('reference position') if !p
1207
+ raise_type_mismatch_error(p, ReferencePosition)
1208
+ @reference_position = p
1209
+ end
1210
+
1211
+ # Some time transformations (e.g., change of RefPos) depend on an assumed directonal position of the source
1212
+ def time_ref_direction=(d)
1213
+ raise_type_mismatch_error(d, AstroCoords) if d
1214
+ @time_ref_direction = d
1215
+ end
1216
+
1217
+ def ==(f)
1218
+ super(f) and
1219
+ self.time_scale == f.time_scale and
1220
+ self.reference_position == f.reference_position and
1221
+ self.time_ref_direction == f.time_ref_direction
1222
+ end
1223
+
1224
+ def to_xml(name=nil)
1225
+ el = super(name)
1226
+
1227
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
1228
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
1229
+
1230
+ time_scale = REXML::Element.new("#{obj_ns.prefix}:TimeScale")
1231
+ time_scale.text = self.time_scale.to_s
1232
+ el.add_element(time_scale)
1233
+
1234
+ el.add_element(self.reference_position.to_xml)
1235
+ el.add_element(self.time_ref_direction.to_xml('TimeRefDirection', obj_ns)) if self.time_ref_direction
1236
+
1237
+ collapse_namespaces(el)
1238
+ el
1239
+ end
1240
+
1241
+ def self.from_xml(xml)
1242
+ root = element_from(xml)
1243
+
1244
+ options = {
1245
+ :reference_position => xml_to_obj(root, ReferencePosition, true),
1246
+ :time_scale => TimeScale.new(REXML::XPath.first(root, 'x:TimeScale', {'x' => obj_ns.uri}).text)
1247
+ }
1248
+
1249
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1250
+ options[:name] = name.text if name
1251
+
1252
+ time_ref_dir = REXML::XPath.first(root, 'x:TimeRefDirection', {'x' => obj_ns.uri})
1253
+ options[:time_ref_direction] = AstroCoords.from_xml(time_ref_dir) if time_ref_dir
1254
+
1255
+ self.new(options)
1256
+ end
1257
+ end
1258
+
1259
+ # The time coordinate reference frame
1260
+ class TimeFrame < TimeFrameType
1261
+ include CoordFrame
1262
+ end
1263
+
1264
+ # ontains the spectral frame reference position
1265
+ class SpectralFrameType < CoordFrameType
1266
+ attr_reader :reference_position
1267
+
1268
+ def initialize(options={})
1269
+ raise_argument_required_error('reference position') if !options.has_key?(:reference_position)
1270
+ super(options)
1271
+ end
1272
+
1273
+ # The reference frame for the Doppler velocities; note presence of LSR
1274
+ def reference_position=(p)
1275
+ raise_argument_required_error('reference position') if !p
1276
+ raise_type_mismatch_error(p, ReferencePosition)
1277
+ @reference_position = p
1278
+ end
1279
+
1280
+ def ==(p)
1281
+ super(p) and self.reference_position == p.reference_position
1282
+ end
1283
+
1284
+ def to_xml(name=nil)
1285
+ el = super(name)
1286
+ el.add_element(self.reference_position.to_xml)
1287
+ collapse_namespaces(el)
1288
+ el
1289
+ end
1290
+
1291
+ def self.from_xml(xml)
1292
+ root = element_from(xml)
1293
+
1294
+ options = {
1295
+ :reference_position => xml_to_obj(root, ReferencePosition, true)
1296
+ }
1297
+
1298
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1299
+ options[:name] = name.text if name
1300
+
1301
+ self.new(options)
1302
+ end
1303
+ end
1304
+
1305
+ # The reference frame for the spectral coordinate; note presence of LSR
1306
+ class SpectralFrame < SpectralFrameType
1307
+ include CoordFrame
1308
+ end
1309
+
1310
+ # The Doppler definition used: optical, radio, or pseudo-relativistic (i.e., how is a redshift
1311
+ # converted to a velocity); the most common is optical, except when the reference is LSR (usually
1312
+ # radio)
1313
+ class DopplerDefinition < Enumeration
1314
+ def self.choices; ['OPTICAL', 'RADIO', 'RELATIVISTIC'] end
1315
+ end
1316
+
1317
+ # Contains the Doppler definitions, including whether the values are velocity or redshift (value_type)
1318
+ class RedshiftFrameType < CoordFrameType
1319
+ attr_reader :doppler_definition, :reference_position
1320
+
1321
+ def initialize(options={})
1322
+ raise_argument_required_error('reference position') if !options.has_key?(:reference_position)
1323
+ super(options)
1324
+ end
1325
+
1326
+ # The Doppler definition used: optical, radio, or pseudo-relativistic (i.e., how is a redshift
1327
+ # converted to a velocity); the most common is optical, except when the reference is LSR (usually
1328
+ # radio)
1329
+ def doppler_definition=(d)
1330
+ d = DopplerDefinition.new(d) if d and d.is_a?(String)
1331
+ raise_type_mismatch_error(d, DopplerDefinition) if d
1332
+ @doppler_definition = d
1333
+ end
1334
+
1335
+ # The reference frame for the Doppler velocities; note presence of LSR
1336
+ def reference_position=(p)
1337
+ raise_argument_required_error('reference position') if !p
1338
+ raise_type_mismatch_error(p, ReferencePosition)
1339
+ @reference_position = p
1340
+ end
1341
+
1342
+ def value_type=(v)
1343
+ @value_type = v ? v.to_s : nil
1344
+ end
1345
+
1346
+ def value_type
1347
+ @value_type || 'VELOCITY'
1348
+ end
1349
+
1350
+ def ==(f)
1351
+ super(f) and
1352
+ self.doppler_definition == f.doppler_definition and
1353
+ self.reference_position == f.reference_position and
1354
+ self.value_type == f.value_type
1355
+ end
1356
+
1357
+ def to_xml(name=nil)
1358
+ el = super(name)
1359
+
1360
+ el.attributes["#{obj_ns.prefix}:value_type"] = self.value_type
1361
+
1362
+ if self.doppler_definition
1363
+ doppler = REXML::Element.new("#{obj_ns.prefix}:DopplerDefinition")
1364
+ doppler.text = doppler_definition.value
1365
+ el.add_element(doppler)
1366
+ end
1367
+
1368
+ el.add_element(self.reference_position.to_xml)
1369
+
1370
+ collapse_namespaces(el)
1371
+ el
1372
+ end
1373
+
1374
+ def self.from_xml(xml)
1375
+ root = element_from(xml)
1376
+
1377
+ options = {
1378
+ :reference_position => xml_to_obj(root, ReferencePosition, true),
1379
+ }
1380
+
1381
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1382
+ options[:name] = name.text if name
1383
+
1384
+ value_type = root.attributes.get_attribute_ns(obj_ns.uri, 'value_type')
1385
+ options[:value_type] = value_type.value if value_type
1386
+
1387
+ doppler_def = REXML::XPath.first(root, 'x:DopplerDefinition', {'x' => obj_ns.uri})
1388
+ options[:doppler_definition] = DopplerDefinition.new(doppler_def.text) if doppler_def
1389
+
1390
+ self.new(options)
1391
+ end
1392
+ end
1393
+
1394
+ # Contains the Doppler definitions, including whether the values are velocity or redshift (value_type)
1395
+ class RedshiftFrame < RedshiftFrameType
1396
+ include CoordFrame
1397
+ end
1398
+
1399
+ # Element for pixel Coordinate Frames
1400
+ class PixelCoordFrame < CoordFrameType
1401
+ include CoordFrame
1402
+
1403
+ def self.from_xml(xml)
1404
+ root = element_from(xml)
1405
+
1406
+ options = {}
1407
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1408
+ options[:name] = name.text if name
1409
+
1410
+ PixelCoordFrame.new(options)
1411
+ end
1412
+ end
1413
+
1414
+ # Element for generic Coordinate Frames
1415
+ class GenericCoordFrame < CoordFrameType
1416
+ include CoordFrame
1417
+
1418
+ def self.from_xml(xml)
1419
+ root = element_from(xml)
1420
+
1421
+ options = {}
1422
+
1423
+ name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
1424
+ options[:name] = name.text if name
1425
+
1426
+ GenericCoordFrame.new(options)
1427
+ end
1428
+ end
1429
+
1430
+ # A CoordSys consists of at least one coordinate frame
1431
+ class CoordSysType
1432
+ include SerializableToXml
1433
+
1434
+ attr_reader :coord_frames, :id
1435
+
1436
+ def initialize(options={})
1437
+ raise_argument_required_error('id') if !options.has_key?(:id)
1438
+ raise_argument_required_error('coordinate frames') if !options.has_key?(:coord_frames)
1439
+ options.each { |key, value| send("#{key}=", value) }
1440
+ end
1441
+
1442
+ def id=(i)
1443
+ raise_argument_required_error('id') if !i
1444
+ i = Id.new(i) if i.is_a?(String)
1445
+ raise_type_mismatch_error(i, Id)
1446
+ @id = i
1447
+ end
1448
+
1449
+ def coord_frames=(fs)
1450
+ raise_argument_required_error('coordinate frames') if !fs
1451
+ fs = CoordFrameList.new(fs) if fs.class == Array
1452
+ raise_type_mismatch_error(fs, CoordFrameList)
1453
+ @coord_frames = fs
1454
+ end
1455
+
1456
+ def ==(c)
1457
+ self.id == c.id and
1458
+ self.coord_frames == c.coord_frames
1459
+ end
1460
+
1461
+ def to_xml(name=nil)
1462
+ el = element(name)
1463
+
1464
+ el.attributes["#{obj_ns.prefix}:ID"] = self.id.to_s
1465
+ self.coord_frames.each { |f| el.add_element(f.to_xml) }
1466
+
1467
+ collapse_namespaces(el)
1468
+ el
1469
+ end
1470
+
1471
+ def self.from_xml(xml)
1472
+ root = element_from(xml)
1473
+
1474
+ options = {
1475
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
1476
+ :coord_frames => xml_to_obj(root, CoordFrame)
1477
+ }
1478
+
1479
+ self.new(options)
1480
+ end
1481
+ end
1482
+
1483
+ class GenericCoordFrameList < TypedArray
1484
+ def self.restricted_to; [GenericCoordFrame] end
1485
+ end
1486
+
1487
+ # The astronomical coordinate system definition: spatial coordinate frame and reference position;
1488
+ # time frame and reference position; the coordinate flavor; spectral frame and (optionally) Doppler
1489
+ # frame; and the planetary ephemeris; an ID is required, since this is how coordinate elements are
1490
+ # associated with their coordinate systems
1491
+ class AstroCoordSystemType < CoordSysType
1492
+ attr_reader :time_frame, :space_frame, :spectral_frame, :redshift_frame, :generic_coord_frames
1493
+
1494
+ def initialize(options={})
1495
+ raise_argument_required_error('time frame') if !options.has_key?(:time_frame)
1496
+ raise_argument_required_error('space frame') if !options.has_key?(:space_frame)
1497
+
1498
+ frames = []
1499
+ frames << options[:time_frame] << options[:space_frame]
1500
+ frames << options[:spectral_frame] if options.has_key?(:spectral_frame)
1501
+ frames << options[:redshift_frame] if options.has_key?(:redshift_frame)
1502
+ options[:generic_coord_frames].each { |f| frames << f } if options.has_key?(:generic_coord_frames) and options[:generic_coord_frames]
1503
+ options[:coord_frames] = frames
1504
+
1505
+ super(options)
1506
+ end
1507
+
1508
+ def time_frame=(f)
1509
+ raise_argument_required_error('time frame') if !f
1510
+ raise_type_mismatch_error(f, TimeFrame)
1511
+ @time_frame = f
1512
+ end
1513
+
1514
+ def space_frame=(f)
1515
+ se_argument_required_error('space frame') if !f
1516
+ raise_type_mismatch_error(f, SpaceFrame)
1517
+ @space_frame = f
1518
+ end
1519
+
1520
+ def spectral_frame=(f)
1521
+ raise_type_mismatch_error(f, SpectralFrame) if f
1522
+ @spectral_frame = f
1523
+ end
1524
+
1525
+ def redshift_frame=(f)
1526
+ raise_type_mismatch_error(f, RedshiftFrame) if f
1527
+ @redshift_frame = f
1528
+ end
1529
+
1530
+ def generic_coord_frames=(fs)
1531
+ if fs
1532
+ fs = GenericCoordFrameList.new(fs) if fs.class == Array
1533
+ raise_type_mismatch_error(fs, GenericCoordFrameList)
1534
+ end
1535
+
1536
+ @generic_coord_frames = fs
1537
+ end
1538
+
1539
+ def ==(s)
1540
+ self.id == s.id and
1541
+ self.time_frame == s.time_frame and
1542
+ self.space_frame == s.space_frame and
1543
+ self.spectral_frame == s.spectral_frame and
1544
+ self.redshift_frame == s.redshift_frame and
1545
+ self.generic_coord_frames == s.generic_coord_frames
1546
+ end
1547
+
1548
+ def coord_frames
1549
+ frames = CoordFrameList.new([self.time_frame, self.space_frame])
1550
+
1551
+ frames << self.spectral_frame if self.spectral_frame
1552
+ frames << self.redshift_frame if self.redshift_frame
1553
+ self.generic_coord_frames.each { |f| frames << f } if self.generic_coord_frames
1554
+
1555
+ frames
1556
+ end
1557
+
1558
+ def coord_frames=(fs)
1559
+ raise_argument_required_error('at least TimeFrame and SpaceFrame') if fs.size < 2
1560
+ self.spectral_frame = self.redshift_frame = self.generic_coord_frames = nil
1561
+
1562
+ raise_type_mismatch_error(fs[0], TimeFrame)
1563
+ self.time_frame = fs[0]
1564
+
1565
+ raise_type_mismatch_error(fs[1], SpaceFrame)
1566
+ self.space_frame = fs[1]
1567
+
1568
+ if fs.size >= 3
1569
+ raise_type_mismatch_error(fs[2], SpectralFrame)
1570
+ self.spectral_frame = fs[2]
1571
+ end
1572
+
1573
+ if fs.size >= 4
1574
+ raise_type_mismatch_error(fs[3], RedshiftFrame)
1575
+ self.redshift_frame = fs[3]
1576
+ end
1577
+
1578
+ if fs.size >= 5
1579
+ fs[4..-1].each do |f|
1580
+ raise_type_mismatch_error(f, GenericCoordFrame)
1581
+ end
1582
+ self.generic_coord_frames = GenericCoordFrameList.new(fs[4..-1])
1583
+ end
1584
+
1585
+ super(fs)
1586
+ end
1587
+
1588
+ def to_xml(name=nil)
1589
+ el = element(name)
1590
+ el.attributes["#{obj_ns.prefix}:ID"] = self.id.to_s
1591
+
1592
+ el.add_element(self.time_frame.to_xml)
1593
+ el.add_element(self.space_frame.to_xml)
1594
+ el.add_element(self.spectral_frame.to_xml) if self.spectral_frame
1595
+ el.add_element(self.redshift_frame.to_xml) if self.redshift_frame
1596
+ self.generic_coord_frames.each{ |f| el.add_element(f.to_xml) } if self.generic_coord_frames
1597
+
1598
+ collapse_namespaces(el)
1599
+ el
1600
+ end
1601
+
1602
+ def self.from_xml(xml)
1603
+ root = element_from(xml)
1604
+
1605
+ options = {
1606
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
1607
+ :time_frame => TimeFrame.from_xml(REXML::XPath.first(root, 'x:TimeFrame', {'x' => obj_ns.uri})),
1608
+ :space_frame => SpaceFrame.from_xml(REXML::XPath.first(root, 'x:SpaceFrame', {'x' => obj_ns.uri}))
1609
+ }
1610
+
1611
+ spectral_frame = REXML::XPath.first(root, 'x:SpectralFrame', {'x' => obj_ns.uri})
1612
+ options[:spectral_frame] = SpectralFrame.from_xml(spectral_frame) if spectral_frame
1613
+
1614
+ redshift_frame = REXML::XPath.first(root, 'x:RedshiftFrame', {'x' => obj_ns.uri})
1615
+ options[:redshift_frame] = RedshiftFrame.from_xml(redshift_frame) if redshift_frame
1616
+
1617
+ generic_coord_frames = REXML::XPath.match(root, 'x:GenericCoordFrame', {'x' => obj_ns.uri})
1618
+ if generic_coord_frames
1619
+ options[:generic_coord_frames] = GenericCoordFrameList.new(
1620
+ generic_coord_frames.collect{ |f| GenericCoordFrame.from_xml(f) }
1621
+ )
1622
+ options[:generic_coord_frames] = nil if options[:generic_coord_frames].size == 0
1623
+ end
1624
+
1625
+ self.new(options)
1626
+ end
1627
+ end
1628
+
1629
+ # The coordinate system definition: spatial coordinate frame and reference position; time frame and reference
1630
+ # position; the coordinate flavor; and the planetary ephemeris; an ID is required, since this is how coordinate
1631
+ # elements are associated with their coordinate systems
1632
+ class AstroCoordSystem < AstroCoordSystemType
1633
+ include CoordSys
1634
+ end
1635
+
1636
+ class PixelCoordFrameList < TypedArray
1637
+ def self.restricted_to; [PixelCoordFrame] end
1638
+ end
1639
+
1640
+ # The pixel coordinate system definition
1641
+ class PixelCoordSystemType < CoordSysType
1642
+ attr_reader :pixel_coord_frames
1643
+
1644
+ def initialize(options={})
1645
+ raise_argument_required_error('list of pixel coordinate systems') if !options.has_key?(:pixel_coord_frames)
1646
+ options[:coord_frames] = options[:pixel_coord_frames]
1647
+ super(options)
1648
+ end
1649
+
1650
+ def pixel_coord_frames=(fs)
1651
+ raise_argument_required_error('list of pixel coordinate systems') if !fs
1652
+
1653
+ fs = PixelCoordFrameList.new(fs) if fs.class == Array
1654
+ raise_type_mismatch_error(fs, PixelCoordFrameList)
1655
+
1656
+ @pixel_coord_frames = fs
1657
+ end
1658
+
1659
+ def coord_frames
1660
+ self.pixel_coord_frames
1661
+ end
1662
+
1663
+ def coord_frames=(cs)
1664
+ self.pixel_coord_frames = cs
1665
+ end
1666
+
1667
+ def ==(f)
1668
+ self.id == f.id and
1669
+ self.pixel_coord_frames == f.pixel_coord_frames
1670
+ end
1671
+
1672
+ def to_xml(name=nil)
1673
+ el = element(name)
1674
+ el.attributes["#{obj_ns.prefix}:ID"] = self.id.to_s
1675
+
1676
+ self.pixel_coord_frames.each { |f| el.add_element(f.to_xml) }
1677
+
1678
+ collapse_namespaces(el)
1679
+ el
1680
+ end
1681
+
1682
+ def self.from_xml(xml)
1683
+ root = element_from(xml)
1684
+
1685
+ options = {
1686
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
1687
+ :pixel_coord_frames => PixelCoordFrameList.new(
1688
+ REXML::XPath.match(root, 'x:PixelCoordFrame', {'x' => obj_ns.uri}).collect { |p| PixelCoordFrame.from_xml(p) }
1689
+ )
1690
+ }
1691
+
1692
+ self.new(options)
1693
+ end
1694
+ end
1695
+
1696
+ # Pixel form of CoordSys
1697
+ class PixelCoordSystem < PixelCoordSystemType
1698
+ include CoordSys
1699
+ end
1700
+
1701
+ # Abstact coordinate interval type
1702
+ class CoordIntervalType
1703
+ include SerializableToXml
1704
+
1705
+ attr_writer :lo_include, :hi_include
1706
+
1707
+ def initialize(options={})
1708
+ options.each { |key, value| send("#{key}=", value) }
1709
+ end
1710
+
1711
+ def lo_include
1712
+ @lo_include == nil ? true : @lo_include
1713
+ end
1714
+
1715
+ def hi_include
1716
+ @hi_include == nil ? true : @hi_include
1717
+ end
1718
+
1719
+ def fill_factor=(f)
1720
+ f = Float(f) if f and !f.is_a?(Float)
1721
+ @fill_factor = f
1722
+ end
1723
+
1724
+ def fill_factor
1725
+ @fill_factor || 1.0
1726
+ end
1727
+
1728
+ def ==(i)
1729
+ self.lo_include == i.lo_include and
1730
+ self.hi_include == i.hi_include and
1731
+ self.fill_factor == i.fill_factor
1732
+ end
1733
+
1734
+ def to_xml(name=nil)
1735
+ el = element(name)
1736
+
1737
+ el.attributes["#{obj_ns.prefix}:lo_include"] = self.lo_include.to_s
1738
+ el.attributes["#{obj_ns.prefix}:hi_include"] = self.hi_include.to_s
1739
+ el.attributes["#{obj_ns.prefix}:fill_factor"] = self.fill_factor.to_s
1740
+
1741
+ el
1742
+ end
1743
+ end
1744
+
1745
+ # The time interval needs to contain a start time or a stop time or both;
1746
+ # it needs to refer to a coordinate system; boundaries may or may not be
1747
+ # inclusive
1748
+ class TimeIntervalType < CoordIntervalType
1749
+ attr_reader :start_time, :stop_time
1750
+
1751
+ # AstronTime may be expressed in ISO8601 or as a double relative to a reference time
1752
+ def start_time=(t)
1753
+ raise_type_mismatch_error(t, AstronTime) if t
1754
+ @start_time = t
1755
+ end
1756
+
1757
+ # AstronTime may be expressed in ISO8601 or as a double relative to a reference time
1758
+ def stop_time=(t)
1759
+ raise_type_mismatch_error(t, AstronTime) if t
1760
+ @stop_time = t
1761
+ end
1762
+
1763
+ def to_xml(name=nil)
1764
+ el = super(name)
1765
+
1766
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
1767
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
1768
+
1769
+ el.add_element(self.start_time.to_xml('StartTime', obj_ns('VORuby::STC::V1_10::STC'))) if self.start_time
1770
+ el.add_element(self.stop_time.to_xml('StopTime', obj_ns('VORuby::STC::V1_10::STC'))) if self.stop_time
1771
+
1772
+ collapse_namespaces(el)
1773
+ el
1774
+ end
1775
+
1776
+ def ==(i)
1777
+ super(i) and
1778
+ self.start_time == i.start_time and
1779
+ self.stop_time == i.stop_time
1780
+ end
1781
+
1782
+ def self.from_xml(xml)
1783
+ root = element_from(xml)
1784
+
1785
+ options = {}
1786
+
1787
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
1788
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
1789
+
1790
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
1791
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
1792
+
1793
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
1794
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
1795
+
1796
+ start_time = REXML::XPath.first(root, 'x:StartTime', {'x' => obj_ns.uri})
1797
+ options[:start_time] = AstronTime.from_xml(start_time) if start_time
1798
+
1799
+ stop_time = REXML::XPath.first(root, 'x:StopTime', {'x' => obj_ns.uri})
1800
+ options[:stop_time] = AstronTime.from_xml(stop_time) if stop_time
1801
+
1802
+ self.new(options)
1803
+ end
1804
+ end
1805
+
1806
+ # Scalar coordinate interval type
1807
+ class CoordScalarIntervalType < CoordIntervalType
1808
+ attr_reader :lo_limit, :hi_limit
1809
+
1810
+ # Lower bound of interval
1811
+ def lo_limit=(l)
1812
+ l = Float(l) if l and !l.is_a?(Float)
1813
+ @lo_limit = l
1814
+ end
1815
+
1816
+ # Upper bound of interval
1817
+ def hi_limit=(l)
1818
+ l = Float(l) if l and !l.is_a?(Float)
1819
+ @hi_limit = l
1820
+ end
1821
+
1822
+ def ==(i)
1823
+ super(i) and
1824
+ self.lo_limit == i.lo_limit and
1825
+ self.hi_limit == i.hi_limit
1826
+ end
1827
+
1828
+ def to_xml(name=nil)
1829
+ el = super(name)
1830
+
1831
+ if self.lo_limit
1832
+ lo_limit = REXML::Element.new("#{obj_ns.prefix}:LoLimit")
1833
+ lo_limit.text = self.lo_limit.to_s
1834
+ el.add_element(lo_limit)
1835
+ end
1836
+
1837
+ if self.hi_limit
1838
+ hi_limit = REXML::Element.new("#{obj_ns.prefix}:HiLimit")
1839
+ hi_limit.text = self.hi_limit.to_s
1840
+ el.add_element(hi_limit)
1841
+ end
1842
+
1843
+ collapse_namespaces(el)
1844
+ el
1845
+ end
1846
+
1847
+ def self.from_xml(xml)
1848
+ root = element_from(xml)
1849
+
1850
+ options = {}
1851
+
1852
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
1853
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
1854
+
1855
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
1856
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
1857
+
1858
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
1859
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
1860
+
1861
+ lo_limit = REXML::XPath.first(root, 'x:LoLimit', {'x' => obj_ns.uri})
1862
+ options[:lo_limit] = Float(lo_limit.text) if lo_limit
1863
+
1864
+ hi_limit = REXML::XPath.first(root, 'x:HiLimit', {'x' => obj_ns.uri})
1865
+ options[:hi_limit] = Float(hi_limit.text) if hi_limit
1866
+
1867
+ self.new(options)
1868
+ end
1869
+ end
1870
+
1871
+ # 2-D coordinate interval type
1872
+ class Coord2VecIntervalType < CoordIntervalType
1873
+ attr_reader :lo_limit, :hi_limit
1874
+
1875
+ def lo_limit=(l)
1876
+ l = Double2.new(l) if l and l.class == Array
1877
+ raise_type_mismatch_error(l, Double2) if l
1878
+
1879
+ @lo_limit = l
1880
+ end
1881
+
1882
+ def hi_limit=(l)
1883
+ l = Double2.new(l) if l and l.class == Array
1884
+ raise_type_mismatch_error(l, Double2) if l
1885
+
1886
+ @hi_limit = l
1887
+ end
1888
+
1889
+ def ==(i)
1890
+ super(i) and
1891
+ self.lo_limit == i.lo_limit and
1892
+ self.hi_limit == i.hi_limit
1893
+ end
1894
+
1895
+ def to_xml(name=nil)
1896
+ el = super(name)
1897
+
1898
+ if self.lo_limit
1899
+ lo_limit = REXML::Element.new("#{obj_ns.prefix}:LoLimit2Vec")
1900
+ lo_limit.text = self.lo_limit.to_s
1901
+ el.add_element(lo_limit)
1902
+ end
1903
+
1904
+ if self.hi_limit
1905
+ hi_limit = REXML::Element.new("#{obj_ns.prefix}:HiLimit2Vec")
1906
+ hi_limit.text = self.hi_limit.to_s
1907
+ el.add_element(hi_limit)
1908
+ end
1909
+
1910
+ collapse_namespaces(el)
1911
+ el
1912
+ end
1913
+
1914
+ def self.from_xml(xml)
1915
+ root = element_from(xml)
1916
+
1917
+ options = {}
1918
+
1919
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
1920
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
1921
+
1922
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
1923
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
1924
+
1925
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
1926
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
1927
+
1928
+ lo_limit = REXML::XPath.first(root, 'x:LoLimit2Vec', {'x' => obj_ns.uri})
1929
+ options[:lo_limit] = Double2.from_xml(lo_limit) if lo_limit
1930
+
1931
+ hi_limit = REXML::XPath.first(root, 'x:HiLimit2Vec', {'x' => obj_ns.uri})
1932
+ options[:hi_limit] = Double2.from_xml(hi_limit) if hi_limit
1933
+
1934
+ self.new(options)
1935
+ end
1936
+ end
1937
+
1938
+ # 2-D coordinate interval type
1939
+ class Coord3VecIntervalType < CoordIntervalType
1940
+ attr_reader :lo_limit, :hi_limit
1941
+
1942
+ def lo_limit=(l)
1943
+ l = Double3.new(l) if l and l.class == Array
1944
+ raise_type_mismatch_error(l, Double3) if l
1945
+
1946
+ @lo_limit = l
1947
+ end
1948
+
1949
+ def hi_limit=(l)
1950
+ l = Double3.new(l) if l and l.class == Array
1951
+ raise_type_mismatch_error(l, Double3) if l
1952
+
1953
+ @hi_limit = l
1954
+ end
1955
+
1956
+ def ==(i)
1957
+ super(i) and
1958
+ self.lo_limit == i.lo_limit and
1959
+ self.hi_limit == i.hi_limit
1960
+ end
1961
+
1962
+ def to_xml(name=nil)
1963
+ el = super(name)
1964
+
1965
+ if self.lo_limit
1966
+ lo_limit = REXML::Element.new("#{obj_ns.prefix}:LoLimit3Vec")
1967
+ lo_limit.text = self.lo_limit.to_s
1968
+ el.add_element(lo_limit)
1969
+ end
1970
+
1971
+ if self.hi_limit
1972
+ hi_limit = REXML::Element.new("#{obj_ns.prefix}:HiLimit3Vec")
1973
+ hi_limit.text = self.hi_limit.to_s
1974
+ el.add_element(hi_limit)
1975
+ end
1976
+
1977
+ collapse_namespaces(el)
1978
+ el
1979
+ end
1980
+
1981
+ def self.from_xml(xml)
1982
+ root = element_from(xml)
1983
+
1984
+ options = {}
1985
+
1986
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
1987
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
1988
+
1989
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
1990
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
1991
+
1992
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
1993
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
1994
+
1995
+ lo_limit = REXML::XPath.first(root, 'x:LoLimit3Vec', {'x' => obj_ns.uri})
1996
+ options[:lo_limit] = Double3.from_xml(lo_limit) if lo_limit
1997
+
1998
+ hi_limit = REXML::XPath.first(root, 'x:HiLimit3Vec', {'x' => obj_ns.uri})
1999
+ options[:hi_limit] = Double3.from_xml(hi_limit) if hi_limit
2000
+
2001
+ self.new(options)
2002
+ end
2003
+ end
2004
+
2005
+ # The spatial coordinate interval substitution group head element; such an
2006
+ # element needs to contain a minimum or maximum scalar or vector value, or
2007
+ # both; it needs to refer to a coordinate system; boundaries may or may not
2008
+ # be inclusive; and it can have a fill factor
2009
+ module CoordInterval; end
2010
+
2011
+ # An interval in a scalar coordinate
2012
+ class CoordScalarInterval < CoordScalarIntervalType
2013
+ include CoordInterval
2014
+ end
2015
+
2016
+ # An interval ("box") in a 2-D coordinate pair
2017
+ class Coord2VecInterval < Coord2VecIntervalType
2018
+ include CoordInterval
2019
+ end
2020
+
2021
+ # An interval ("cube") in a 3-D coordinate triplet
2022
+ class Coord3VecInterval < Coord3VecIntervalType
2023
+ include CoordInterval
2024
+ end
2025
+
2026
+ # Parent type for spatial intervals
2027
+ class SpatialIntervalType
2028
+ include SerializableToXml
2029
+
2030
+ def initialize(options={})
2031
+ options.each { |key, value| send("#{key}=", value) }
2032
+ end
2033
+ end
2034
+
2035
+ # Defines a sphere
2036
+ class SphereType < SpatialIntervalType
2037
+ attr_reader :radius, :center, :unit
2038
+
2039
+ def initialize(options={})
2040
+ raise_argument_required_error('radius') if !options.has_key?(:radius)
2041
+ raise_argument_required_error('center') if !options.has_key?(:center)
2042
+ raise_argument_required_error('unit') if !options.has_key?(:unit)
2043
+ super(options)
2044
+ end
2045
+
2046
+ def radius=(r)
2047
+ raise_argument_required_error('radius') if !r
2048
+ r = Float(r) if !r.is_a?(Float)
2049
+ @radius = r
2050
+ end
2051
+
2052
+ def center=(c)
2053
+ raise_argument_required_error('center') if !c
2054
+ c = Double3.new(c) if c.class == Array
2055
+ raise_type_mismatch_error(c, Double3)
2056
+ @center = c
2057
+ end
2058
+
2059
+ def unit=(u)
2060
+ raise_argument_required_error('unit') if !u
2061
+ u = PosUnit.new(u.to_s) if !u.is_a?(PosUnit)
2062
+ raise_type_mismatch_error(u, PosUnit)
2063
+ @unit = u
2064
+ end
2065
+
2066
+ def radius_unit=(u)
2067
+ u = PosUnit.new(u.to_s) if u and !u.is_a?(PosUnit)
2068
+ raise_type_mismatch_error(u, PosUnit) if u
2069
+ @radius_unit = u
2070
+ end
2071
+
2072
+ def radius_unit
2073
+ @radius_unit || PosUnit.new('deg')
2074
+ end
2075
+
2076
+ def fill_factor=(f)
2077
+ f = Float(f) if !f.is_a?(Float)
2078
+ @fill_factor = f
2079
+ end
2080
+
2081
+ def fill_factor
2082
+ @fill_factor || 1.0
2083
+ end
2084
+
2085
+ def ==(s)
2086
+ self.radius == s.radius and
2087
+ self.center == s.center and
2088
+ self.unit == s.unit and
2089
+ self.radius_unit == s.radius_unit and
2090
+ self.fill_factor == s.fill_factor
2091
+ end
2092
+
2093
+ def to_xml(name=nil)
2094
+ el = element(name)
2095
+
2096
+ el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
2097
+ el.attributes["#{obj_ns.prefix}:radius_unit"] = self.radius_unit.to_s if self.radius_unit
2098
+ el.attributes["#{obj_ns.prefix}:fill_factor"] = self.fill_factor.to_s if self.fill_factor
2099
+
2100
+ radius = REXML::Element.new("#{obj_ns.prefix}:Radius")
2101
+ radius.text = self.radius.to_s
2102
+ el.add_element(radius)
2103
+
2104
+ center = REXML::Element.new("#{obj_ns.prefix}:Center")
2105
+ center.text = self.center.to_s
2106
+ el.add_element(center)
2107
+
2108
+ collapse_namespaces(el)
2109
+ el
2110
+ end
2111
+
2112
+ def self.from_xml(xml)
2113
+ root = element_from(xml)
2114
+
2115
+ options = {
2116
+ :radius => Float(REXML::XPath.first(root, 'x:Radius', {'x' => obj_ns.uri}).text),
2117
+ :center => Double3.from_xml(REXML::XPath.first(root, 'x:Center', {'x' => obj_ns.uri})),
2118
+ :unit => PosUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'unit').value)
2119
+ }
2120
+
2121
+ radius_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'radius_unit')
2122
+ options[:radius_unit] = PosUnit.new(radius_unit.value) if radius_unit
2123
+
2124
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
2125
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
2126
+
2127
+ self.new(options)
2128
+ end
2129
+ end
2130
+
2131
+ # Defines a velocity sphere.
2132
+ # A special kind of area is a circle or sphere (in two or three dimensions),
2133
+ # defined by a center position and a radius; the radius requires a unit
2134
+ class VelocitySphereType < SphereType
2135
+ attr_reader :vel_time_unit
2136
+
2137
+ def initialize(options={})
2138
+ raise_argument_required_error('velocity time unit') if !options.has_key?(:vel_time_unit)
2139
+ super(options)
2140
+ end
2141
+
2142
+ def vel_time_unit=(u)
2143
+ raise_argument_required_error('velocity time unit') if !u
2144
+
2145
+ u = VelTimeUnit.new(u) if u.is_a?(String)
2146
+ raise_type_mismatch_error(u, VelTimeUnit)
2147
+
2148
+ @vel_time_unit = u
2149
+ end
2150
+
2151
+ def ==(s)
2152
+ super(s) and self.vel_time_unit == s.vel_time_unit
2153
+ end
2154
+
2155
+ def to_xml(name=nil)
2156
+ el = super(name)
2157
+ el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s
2158
+ el
2159
+ end
2160
+
2161
+ def self.from_xml(xml)
2162
+ root = element_from(xml)
2163
+
2164
+ options = {
2165
+ :radius => Float(REXML::XPath.first(root, 'x:Radius', {'x' => obj_ns.uri}).text),
2166
+ :center => Double3.from_xml(REXML::XPath.first(root, 'x:Center', {'x' => obj_ns.uri})),
2167
+ :unit => PosUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'unit').value),
2168
+ :vel_time_unit => VelTimeUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit').value)
2169
+ }
2170
+
2171
+ radius_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'radius_unit')
2172
+ options[:radius_unit] = PosUnit.new(radius_unit.value) if radius_unit
2173
+
2174
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
2175
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
2176
+
2177
+ self.new(options)
2178
+ end
2179
+ end
2180
+
2181
+ # Contains a spatial position CoordInterval
2182
+ class PositionIntervalType < SpatialIntervalType
2183
+ attr_reader :coord_interval, :unit
2184
+
2185
+ def initialize(options={})
2186
+ raise_argument_required_error('coordinate interval') if !options.has_key?(:coord_interval)
2187
+ raise_argument_required_error('unit') if !options.has_key?(:unit)
2188
+ super(options)
2189
+ end
2190
+
2191
+ def coord_interval=(i)
2192
+ raise_argument_required_error('coordinate interval') if !i
2193
+ raise_type_mismatch_error(i, CoordInterval)
2194
+ @coord_interval = i
2195
+ end
2196
+
2197
+ def unit=(u)
2198
+ raise_argument_required_error('unit') if !u
2199
+ raise_type_mismatch_error(u, PosUnit)
2200
+ @unit = u
2201
+ end
2202
+
2203
+ def ==(i)
2204
+ self.coord_interval == i.coord_interval and
2205
+ self.unit == i.unit
2206
+ end
2207
+
2208
+ def to_xml(name=nil)
2209
+ el = element(name)
2210
+ el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
2211
+ el.add_element(self.coord_interval.to_xml)
2212
+ el
2213
+ end
2214
+
2215
+ def self.from_xml(xml)
2216
+ root = element_from(xml)
2217
+
2218
+ options = {
2219
+ :unit => PosUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'unit').value),
2220
+ :coord_interval => xml_to_obj(root, CoordInterval, true)
2221
+ }
2222
+
2223
+ self.new(options)
2224
+ end
2225
+ end
2226
+
2227
+ # Contains a spatial velocity CoordInterval.
2228
+ # A special kind of area is a circle or sphere (in two or three dimensions),
2229
+ # defined by a center position and a radius; the radius requires a unit
2230
+ class VelocityIntervalType < PositionIntervalType
2231
+ attr_reader :vel_time_unit
2232
+
2233
+ def initialize(options={})
2234
+ raise_argument_required_error('velocity time unit') if !options.has_key?(:vel_time_unit)
2235
+ super(options)
2236
+ end
2237
+
2238
+ def vel_time_unit=(u)
2239
+ raise_argument_required_error('velocity time unit') if !u
2240
+
2241
+ u = VelTimeUnit.new(u) if u.is_a?(String)
2242
+ raise_type_mismatch_error(u, VelTimeUnit)
2243
+
2244
+ @vel_time_unit = u
2245
+ end
2246
+
2247
+ def ==(s)
2248
+ super(s) and self.vel_time_unit == s.vel_time_unit
2249
+ end
2250
+
2251
+ def to_xml(name=nil)
2252
+ el = super(name)
2253
+ el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s
2254
+ el
2255
+ end
2256
+
2257
+ def self.from_xml(xml)
2258
+ root = element_from(xml)
2259
+
2260
+ options = {
2261
+ :unit => PosUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'unit').value),
2262
+ :vel_time_unit => VelTimeUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit').value),
2263
+ :coord_interval => xml_to_obj(root, CoordInterval, true)
2264
+ }
2265
+
2266
+ self.new(options)
2267
+ end
2268
+ end
2269
+
2270
+ # Points to a Region file
2271
+ class RegionFileType < SpatialIntervalType
2272
+ attr_reader :file
2273
+
2274
+ def initialize(options={})
2275
+ raise_argument_required_error('file') if !options.has_key?(:file)
2276
+ super(options)
2277
+ end
2278
+
2279
+ def file=(f)
2280
+ raise_argument_required_error('file') if !f
2281
+ @file = URI.parse(f.to_s)
2282
+ end
2283
+
2284
+ def ==(f)
2285
+ self.file == f.file
2286
+ end
2287
+
2288
+ def to_xml(name=nil)
2289
+ el = element(name)
2290
+
2291
+ file = REXML::Element.new("#{obj_ns.prefix}:File")
2292
+ file.text = self.file.to_s
2293
+ el.add_element(file)
2294
+
2295
+ el
2296
+ end
2297
+
2298
+ def self.from_xml(xml)
2299
+ root = element_from(xml)
2300
+
2301
+ options = {
2302
+ :file => URI.parse(REXML::XPath.first(root, 'x:File', {'x' => obj_ns.uri}).text)
2303
+ }
2304
+
2305
+ self.new(options)
2306
+ end
2307
+ end
2308
+
2309
+ # Contains an abstract Region
2310
+ class RegionType < SpatialIntervalType
2311
+ attr_reader :region
2312
+
2313
+ def initialize(options={})
2314
+ raise_argument_required_error('region') if !options.has_key?(:region)
2315
+ super(options)
2316
+ end
2317
+
2318
+ def region=(r)
2319
+ raise_argument_required_error('region') if !r
2320
+ raise_type_mismatch_error(r, V1_10::Region::Region)
2321
+ @region = r
2322
+ end
2323
+
2324
+ def ==(r)
2325
+ self.region == r.region
2326
+ end
2327
+
2328
+ def to_xml(name=nil)
2329
+ el = element(name)
2330
+
2331
+ coords_ns = NAMESPACES['VORuby::STC::V1_10::Coords']
2332
+ el.add_namespace(coords_ns.prefix, coords_ns.uri)
2333
+
2334
+ region_ns = NAMESPACES['VORuby::STC::V1_10::Region']
2335
+ el.add_namespace(region_ns.prefix, region_ns.uri)
2336
+
2337
+ el.add_element(self.region.to_xml)
2338
+
2339
+ collapse_namespaces(el)
2340
+ el
2341
+ end
2342
+
2343
+ def self.from_xml(xml)
2344
+ root = element_from(xml)
2345
+
2346
+ options = {
2347
+ :region => xml_to_obj(root, V1_10::Region::Region, true, V1_10::Region)
2348
+ }
2349
+
2350
+ self.new(options)
2351
+ end
2352
+ end
2353
+
2354
+ # The spatial interval substitution group head element;
2355
+ # a spatial coordinate interval (volume) is specified as
2356
+ # a circle (cone) or sphere; a 1-D, 2-D, or 3-D interval;
2357
+ # a Region; or a RegionFile
2358
+ module SpatialInterval; end
2359
+
2360
+ # Defines a sphere (3-D) region for spatial coordinates;
2361
+ # contains a center position and a radius
2362
+ class Sphere < SphereType
2363
+ include SpatialInterval
2364
+ end
2365
+
2366
+ # Contains a CoordInterval element: a 1-D range, 2-D box, or 3-D cube
2367
+ class PositionInterval < PositionIntervalType
2368
+ include SpatialInterval
2369
+ end
2370
+
2371
+ # A region as defined in a FITS region file
2372
+ class RegionFile < RegionFileType
2373
+ include SpatialInterval
2374
+ end
2375
+
2376
+ # Contains a region as defined in the Region schema
2377
+ class Region < RegionType
2378
+ include SpatialInterval
2379
+ end
2380
+
2381
+ # Contains a Velocity CoordInterval element: a 1-D range, 2-D box, or 3-D cube;
2382
+ # plus a time unit for velocity values
2383
+ module VelInterval; end
2384
+
2385
+ # Defines a sphere (3-D) region for velocity coordinates; contains a center position and a radius
2386
+ class VelocitySphere < VelocitySphereType
2387
+ include VelInterval
2388
+ end
2389
+
2390
+ # Contains a CoordInterval element: a 1-D range, 2-D box, or 3-D cube
2391
+ class VelocityInterval < VelocityIntervalType
2392
+ include VelInterval
2393
+ end
2394
+
2395
+ # Contains a 1-D spectral interval
2396
+ class SpectralInterval < CoordScalarIntervalType
2397
+ attr_reader :unit
2398
+
2399
+ def initialize(options={})
2400
+ raise_argument_required_error('unit') if !options.has_key?(:unit)
2401
+ super(options)
2402
+ end
2403
+
2404
+ def unit=(u)
2405
+ raise_argument_required_error('unit') if !u
2406
+
2407
+ u = SpectralUnit.new(u) if u.is_a?(String)
2408
+ raise_type_mismatch_error(u, SpectralUnit)
2409
+
2410
+ @unit = u
2411
+ end
2412
+
2413
+ def ==(i)
2414
+ super(i) and self.unit = i.unit
2415
+ end
2416
+
2417
+ def to_xml(name=nil)
2418
+ el = super(name)
2419
+ el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
2420
+ el
2421
+ end
2422
+
2423
+ def self.from_xml(xml)
2424
+ root = element_from(xml)
2425
+
2426
+ options = {}
2427
+
2428
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
2429
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
2430
+
2431
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
2432
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
2433
+
2434
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
2435
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
2436
+
2437
+ lo_limit = REXML::XPath.first(root, 'x:LoLimit', {'x' => obj_ns.uri})
2438
+ options[:lo_limit] = Float(lo_limit.text) if lo_limit
2439
+
2440
+ hi_limit = REXML::XPath.first(root, 'x:HiLimit', {'x' => obj_ns.uri})
2441
+ options[:hi_limit] = Float(hi_limit.text) if hi_limit
2442
+
2443
+ options[:unit] = SpectralUnit.new(root.attributes.get_attribute_ns(obj_ns.uri, 'unit').value)
2444
+
2445
+ self.new(options)
2446
+ end
2447
+ end
2448
+
2449
+ # Contains a 1-D redshift interval; position and time units are required if redshifts
2450
+ # are expressed as Doppler velocities
2451
+ class RedshiftInterval < CoordScalarIntervalType
2452
+ attr_reader :unit, :vel_time_unit
2453
+
2454
+ def unit=(u)
2455
+ u = PosUnit.new(u) if u.is_a?(String)
2456
+ raise_type_mismatch_error(u, PosUnit) if u
2457
+ @unit = u
2458
+ end
2459
+
2460
+ def vel_time_unit=(u)
2461
+ u = VelTimeUnit.new(u) if u.is_a?(String)
2462
+ raise_type_mismatch_error(u, VelTimeUnit) if u
2463
+ @vel_time_unit = u
2464
+ end
2465
+
2466
+ def ==(i)
2467
+ super(i) and
2468
+ self.unit == i.unit and
2469
+ self.vel_time_unit == i.vel_time_unit
2470
+ end
2471
+
2472
+ def to_xml(name=nil)
2473
+ el = super(name)
2474
+
2475
+ el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
2476
+ el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s if self.vel_time_unit
2477
+
2478
+ el
2479
+ end
2480
+
2481
+ def self.from_xml(xml)
2482
+ root = element_from(xml)
2483
+
2484
+ options = {}
2485
+
2486
+ lo_include = root.attributes.get_attribute_ns(obj_ns.uri, 'lo_include')
2487
+ options[:lo_include] = (lo_include.value == 'true' ? true : false) if lo_include
2488
+
2489
+ hi_include = root.attributes.get_attribute_ns(obj_ns.uri, 'hi_include')
2490
+ options[:hi_include] = (hi_include.value == 'true' ? true : false) if hi_include
2491
+
2492
+ fill_factor = root.attributes.get_attribute_ns(obj_ns.uri, 'fill_factor')
2493
+ options[:fill_factor] = Float(fill_factor.value) if fill_factor
2494
+
2495
+ lo_limit = REXML::XPath.first(root, 'x:LoLimit', {'x' => obj_ns.uri})
2496
+ options[:lo_limit] = Float(lo_limit.text) if lo_limit
2497
+
2498
+ hi_limit = REXML::XPath.first(root, 'x:HiLimit', {'x' => obj_ns.uri})
2499
+ options[:hi_limit] = Float(hi_limit.text) if hi_limit
2500
+
2501
+ unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
2502
+ options[:unit] = PosUnit.new(unit.value) if unit
2503
+
2504
+ vel_time_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit')
2505
+ options[:vel_time_unit] = VelTimeUnit.new(vel_time_unit.value) if vel_time_unit
2506
+
2507
+ self.new(options)
2508
+ end
2509
+ end
2510
+
2511
+ class TimeIntervalList < TypedArray
2512
+ def self.restricted_to; [TimeIntervalType] end
2513
+ end
2514
+
2515
+ class VelIntervalList < TypedArray
2516
+ def self.restricted_to; [VelInterval] end
2517
+ end
2518
+
2519
+ class SpectralIntervalList < TypedArray
2520
+ def self.restricted_to; [SpectralInterval] end
2521
+ end
2522
+
2523
+ class RedshiftIntervalList < TypedArray
2524
+ def self.restricted_to; [RedshiftInterval] end
2525
+ end
2526
+
2527
+ class CoordIntervalList < TypedArray
2528
+ def self.restricted_to; [CoordInterval] end
2529
+ end
2530
+
2531
+ class CoordScalarIntervalList < TypedArray
2532
+ def self.restricted_to; [CoordScalarInterval] end
2533
+ end
2534
+
2535
+ # Generalized coordinate area type
2536
+ class CoordAreaType
2537
+ include SerializableToXml
2538
+
2539
+ attr_reader :time_intervals, :spatial_interval, :vel_intervals,
2540
+ :spectral_intervals, :redshift_intervals, :coord_intervals,
2541
+ :id, :coord_system_id
2542
+
2543
+ def initialize(options={})
2544
+ raise_argument_required_error('id') if !options.has_key?(:id)
2545
+ raise_argument_required_error('coord system id') if !options.has_key?(:coord_system_id)
2546
+ options.each { |key, value| send("#{key}=", value) }
2547
+ end
2548
+
2549
+ def time_intervals=(is)
2550
+ if is
2551
+ is = TimeIntervalList.new(is) if is.class == Array
2552
+ raise_type_mismatch_error(is, TimeIntervalList)
2553
+ end
2554
+ @time_intervals = is
2555
+ end
2556
+
2557
+ def spatial_interval=(i)
2558
+ raise_type_mismatch_error(i, SpatialInterval) if i
2559
+ @spatial_interval = i
2560
+ end
2561
+
2562
+ def vel_intervals=(is)
2563
+ if is
2564
+ is = VelIntervalList.new(is) if is.class == Array
2565
+ raise_type_mismatch_error(is, VelIntervalList)
2566
+ end
2567
+ @vel_intervals = is
2568
+ end
2569
+
2570
+ def spectral_intervals=(is)
2571
+ if is
2572
+ is = SpectralIntervalList.new(is) if is.class == Array
2573
+ raise_type_mismatch_error(is, SpectralIntervalList)
2574
+ end
2575
+ @spectral_intervals = is
2576
+ end
2577
+
2578
+ def redshift_intervals=(is)
2579
+ if is
2580
+ is = RedshiftIntervalList.new(is) if is.class == Array
2581
+ raise_type_mismatch_error(is, RedshiftIntervalList)
2582
+ end
2583
+ @redshift_intervals = is
2584
+ end
2585
+
2586
+ def coord_intervals=(is)
2587
+ if is
2588
+ is = CoordIntervalList.new(is) if is.class == Array
2589
+ raise_type_mismatch_error(is, CoordIntervalList)
2590
+ end
2591
+ @coord_intervals = is
2592
+ end
2593
+
2594
+ def id=(i)
2595
+ raise_argument_required_error('id') if !i
2596
+
2597
+ i = Id.new(i) if i.is_a?(String)
2598
+ raise_type_mismatch_error(i, Id)
2599
+
2600
+ @id = i
2601
+ end
2602
+
2603
+ def coord_system_id=(ref)
2604
+ raise_argument_required_error('coord system id') if !ref
2605
+
2606
+ ref = IdRef.new(ref) if ref.is_a?(String)
2607
+ raise_type_mismatch_error(ref, IdRef)
2608
+
2609
+ @coord_system_id = ref
2610
+ end
2611
+
2612
+ def ==(a)
2613
+ self.time_intervals == a.time_intervals and
2614
+ self.spatial_interval == a.spatial_interval and
2615
+ self.vel_intervals == a.vel_intervals and
2616
+ self.spectral_intervals == a.spectral_intervals and
2617
+ self.redshift_intervals == a.redshift_intervals and
2618
+ self.coord_intervals == a.coord_intervals and
2619
+ self.id == a.id and
2620
+ self.coord_system_id == a.coord_system_id
2621
+ end
2622
+
2623
+ def to_xml(name=nil)
2624
+ el = element(name)
2625
+
2626
+ el.attributes["#{obj_ns.prefix}:ID"] = self.id.to_s
2627
+ el.attributes["#{obj_ns.prefix}:coord_system_id"] = self.coord_system_id.to_s
2628
+
2629
+ self.time_intervals.each { |i| el.add_element(i.to_xml('TimeInterval')) } if self.time_intervals
2630
+ el.add_element(self.spatial_interval.to_xml) if self.spatial_interval
2631
+ self.vel_intervals.each { |i| el.add_element(i.to_xml) } if self.vel_intervals
2632
+ self.spectral_intervals.each { |i| el.add_element(i.to_xml('SpectralInterval')) } if self.spectral_intervals
2633
+ self.redshift_intervals.each { |i| el.add_element(i.to_xml('RedshiftInterval')) } if self.redshift_intervals
2634
+ self.coord_intervals.each { |i| el.add_element(i.to_xml) } if self.coord_intervals
2635
+
2636
+ collapse_namespaces(el)
2637
+ el
2638
+ end
2639
+
2640
+ def self.from_xml(xml)
2641
+ root = element_from(xml)
2642
+
2643
+ options = {
2644
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
2645
+ :coord_system_id => IdRef.new(root.attributes.get_attribute_ns(obj_ns.uri, 'coord_system_id').value)
2646
+ }
2647
+
2648
+ time_intervals = REXML::XPath.match(root, 'x:TimeInterval', {'x' => obj_ns.uri})
2649
+ options[:time_intervals] = TimeIntervalList.new(time_intervals.collect{ |i| TimeIntervalType.from_xml(i) }) if time_intervals
2650
+
2651
+ options[:spatial_interval] = xml_to_obj(root, SpatialInterval, true)
2652
+
2653
+ options[:vel_intervals] = xml_to_obj(root, VelInterval)
2654
+ options[:vel_intervals] = nil if options[:vel_intervals].size == 0
2655
+
2656
+ spectral_intervals = REXML::XPath.match(root, 'x:SpectralInterval', {'x' => obj_ns.uri})
2657
+ options[:spectral_intervals] = SpectralIntervalList.new(spectral_intervals.collect{ |i| SpectralInterval.from_xml(i) }) if spectral_intervals
2658
+ options[:spectral_intervals] = nil if spectral_intervals and options[:spectral_intervals].size == 0
2659
+
2660
+ redshift_intervals = REXML::XPath.match(root, 'x:RedshiftInterval', {'x' => obj_ns.uri})
2661
+ options[:redshift_intervals] = RedshiftIntervalList.new(redshift_intervals.collect{ |i| RedshiftInterval.from_xml(i) }) if redshift_intervals
2662
+ options[:redshift_intervals] = nil if redshift_intervals and options[:redshift_intervals].size == 0
2663
+
2664
+ options[:coord_intervals] = xml_to_obj(root, CoordInterval)
2665
+ options[:coord_intervals] = nil if options[:coord_intervals].size == 0
2666
+
2667
+ self.new(options)
2668
+ end
2669
+ end
2670
+
2671
+ class AstroCoordAreaType < CoordAreaType
2672
+ def coord_intervals=(is)
2673
+ if is
2674
+ is = CoordScalarIntervalList.new(is) if is.class == Array
2675
+ raise_type_mismatch_error(is, CoordScalarIntervalList)
2676
+ end
2677
+ @coord_intervals = is
2678
+ end
2679
+
2680
+ def self.from_xml(xml)
2681
+ root = element_from(xml)
2682
+
2683
+ options = {
2684
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
2685
+ :coord_system_id => IdRef.new(root.attributes.get_attribute_ns(obj_ns.uri, 'coord_system_id').value)
2686
+ }
2687
+
2688
+ time_intervals = REXML::XPath.match(root, 'x:TimeInterval', {'x' => obj_ns.uri})
2689
+ options[:time_intervals] = TimeIntervalList.new(time_intervals.collect{ |i| TimeIntervalType.from_xml(i) }) if time_intervals
2690
+
2691
+ options[:spatial_interval] = xml_to_obj(root, SpatialInterval, true)
2692
+
2693
+ options[:vel_intervals] = xml_to_obj(root, VelInterval)
2694
+ options[:vel_intervals] = nil if options[:vel_intervals].size == 0
2695
+
2696
+ spectral_intervals = REXML::XPath.match(root, 'x:SpectralInterval', {'x' => obj_ns.uri})
2697
+ options[:spectral_intervals] = SpectralIntervalList.new(spectral_intervals.collect{ |i| SpectralInterval.from_xml(i) }) if spectral_intervals
2698
+ options[:spectral_intervals] = nil if options[:spectral_intervals].size == 0
2699
+
2700
+ redshift_intervals = REXML::XPath.match(root, 'x:RedshiftInterval', {'x' => obj_ns.uri})
2701
+ options[:redshift_intervals] = RedshiftIntervalList.new(redshift_intervals.collect{ |i| RedshiftInterval.from_xml(i) }) if redshift_intervals
2702
+ options[:redshift_intervals] = nil if options[:redshift_intervals].size == 0
2703
+
2704
+ options[:coord_intervals] = xml_to_obj(root, CoordScalarInterval)
2705
+ options[:coord_intervals] = nil if options[:coord_intervals].size == 0
2706
+
2707
+ self.new(options)
2708
+ end
2709
+ end
2710
+
2711
+ class PixelCoordAreaType < CoordAreaType
2712
+ attr_reader :coord_intervals
2713
+
2714
+ class CoordScalarIntervalList < CoordScalarIntervalList
2715
+ def self.minimum_length; 1 end
2716
+ end
2717
+
2718
+ def initialize(options={})
2719
+ raise_argument_required_error('list of coordinate scalar intervals') if !options.has_key?(:coord_intervals)
2720
+ super(options)
2721
+ end
2722
+
2723
+ def coord_intervals=(is)
2724
+ raise_argument_required_error('list of coordinate scalar intervals') if !is
2725
+
2726
+ is = PixelCoordAreaType::CoordScalarIntervalList.new(is) if is.class == Array
2727
+ raise_type_mismatch_error(is, PixelCoordAreaType::CoordScalarIntervalList)
2728
+
2729
+ @coord_intervals = is
2730
+ end
2731
+
2732
+ def self.from_xml(xml)
2733
+ root = element_from(xml)
2734
+
2735
+ options = {
2736
+ :id => Id.new(root.attributes.get_attribute_ns(obj_ns.uri, 'ID').value),
2737
+ :coord_system_id => IdRef.new(root.attributes.get_attribute_ns(obj_ns.uri, 'coord_system_id').value)
2738
+ }
2739
+
2740
+ time_intervals = REXML::XPath.match(root, 'x:TimeInterval', {'x' => obj_ns.uri})
2741
+ options[:time_intervals] = TimeIntervalList.new(time_intervals.collect{ |i| TimeIntervalType.from_xml(i) }) if time_intervals
2742
+ options[:time_intervals] = nil if time_intervals and options[:time_intervals].size == 0
2743
+
2744
+ options[:spatial_interval] = xml_to_obj(root, SpatialInterval, true)
2745
+
2746
+ options[:vel_intervals] = xml_to_obj(root, VelInterval)
2747
+ options[:vel_intervals] = nil if options[:vel_intervals].size == 0
2748
+
2749
+ spectral_intervals = REXML::XPath.match(root, 'x:SpectralInterval', {'x' => obj_ns.uri})
2750
+ options[:spectral_intervals] = SpectralIntervalList.new(spectral_intervals.collect{ |i| SpectralInterval.from_xml(i) }) if spectral_intervals
2751
+ options[:spectral_intervals] = nil if spectral_intervals and options[:spectral_intervals].size == 0
2752
+
2753
+ redshift_intervals = REXML::XPath.match(root, 'x:RedshiftInterval', {'x' => obj_ns.uri})
2754
+ options[:redshift_intervals] = RedshiftIntervalList.new(redshift_intervals.collect{ |i| RedshiftInterval.from_xml(i) }) if redshift_intervals
2755
+ options[:redshift_intervals] = nil if redshift_intervals and options[:redshift_intervals].size == 0
2756
+
2757
+ options[:coord_intervals] = xml_to_obj(root, CoordScalarInterval)
2758
+ options[:coord_intervals] = nil if options[:coord_intervals].size == 0
2759
+
2760
+ self.new(options)
2761
+ end
2762
+ end
2763
+
2764
+ # General coordinate area description; head element but not abstract
2765
+ module CoordArea; end
2766
+
2767
+ # Astronomical coordinate volume
2768
+ class AstroCoordArea < AstroCoordAreaType
2769
+ include CoordArea
2770
+ end
2771
+
2772
+ # Pixel space bounds
2773
+ class PixelCoordArea < PixelCoordAreaType
2774
+ include CoordArea
2775
+ end
2776
+
2777
+ # Abstract stcMetadata type
2778
+ class StcMetadataType
2779
+ include SerializableToXml
2780
+
2781
+ attr_reader :id
2782
+
2783
+ def initialize(options={})
2784
+ options.each { |key, value| send("#{key}=", value) }
2785
+ end
2786
+
2787
+ def id=(i)
2788
+ i = Id.new(i) if i and i.is_a?(String)
2789
+ raise_type_mismatch_error(i, Id) if i
2790
+ @id = i
2791
+ end
2792
+
2793
+ def ==(m)
2794
+ self.id == m.id
2795
+ end
2796
+
2797
+ def to_xml(name=nil)
2798
+ el = element(name)
2799
+ el.attributes["#{obj_ns.prefix}:ID"] = self.id.to_s if self.id
2800
+ el
2801
+ end
2802
+ end
2803
+
2804
+ class CoordsList < TypedArray
2805
+ def self.restricted_to; [Coords] end
2806
+ end
2807
+
2808
+ class CoordAreaList < TypedArray
2809
+ def self.restricted_to; [CoordArea] end
2810
+ end
2811
+
2812
+ # Generalized single stcMetadata type
2813
+ class StcDescription < StcMetadataType
2814
+ attr_reader :coord_sys, :coords, :coord_areas
2815
+
2816
+ class CoordSysList < TypedArray
2817
+ def self.restricted_to; [CoordSys] end
2818
+ def self.minimum_length; 1 end
2819
+ end
2820
+
2821
+ def initialize(options={})
2822
+ raise_argument_required_error('list of coordinate systems') if !options.has_key?(:coord_sys)
2823
+ super(options)
2824
+ end
2825
+
2826
+ def coord_sys=(ss)
2827
+ raise_argument_required_error('list of coordinate systems') if !ss
2828
+
2829
+ ss = StcDescription::CoordSysList.new(ss) if ss.class == Array
2830
+ raise_type_mismatch_error(ss, StcDescription::CoordSysList)
2831
+
2832
+ @coord_sys = ss
2833
+ end
2834
+
2835
+ def coords=(cs)
2836
+ cs = CoordsList.new(cs) if cs and cs.class == Array
2837
+ raise_type_mismatch_error(cs, CoordsList) if cs
2838
+ @coords = cs
2839
+ end
2840
+
2841
+ def coord_areas=(cs)
2842
+ cs = CoordAreaList.new(cs) if cs and cs.class == Array
2843
+ raise_type_mismatch_error(cs, CoordAreaList) if cs
2844
+ @coord_areas = cs
2845
+ end
2846
+
2847
+ def ==(d)
2848
+ super(d) and
2849
+ self.coord_sys == d.coord_sys and
2850
+ self.coords == d.coords and
2851
+ self.coord_areas == d.coord_areas
2852
+ end
2853
+
2854
+ def to_xml(name=nil)
2855
+ el = super(name)
2856
+
2857
+ if self.coord_sys
2858
+ self.coord_sys.is_a?(Array) ? self.coord_sys.each { |s| el.add_element(s.to_xml) } : el.add_element(self.coord_sys.to_xml)
2859
+ end
2860
+
2861
+ if self.coords
2862
+ self.coords.is_a?(Array) ? self.coords.each { |c| el.add_element(c.to_xml) } : el.add_element(self.coords.to_xml)
2863
+ end
2864
+
2865
+ if self.coord_areas
2866
+ self.coord_areas.is_a?(Array) ? self.coord_areas.each { |a| el.add_element(a.to_xml) } : el.add_element(self.coord_areas.to_xml)
2867
+ end
2868
+
2869
+ collapse_namespaces(el)
2870
+ el
2871
+ end
2872
+ end
2873
+
2874
+ class AstroCoordSystemList < TypedArray
2875
+ def self.restricted_to; [AstroCoordSystem] end
2876
+ def self.minimum_length; 1 end
2877
+ end
2878
+
2879
+ # Type for STC Resource Profile
2880
+ class StcResourceProfileType < StcDescription
2881
+ def initialize(options={})
2882
+ raise_argument_required_error('astro coordinate systems') if !options.has_key?(:coord_sys)
2883
+ raise_argument_required_error('astro coordinate') if !options.has_key?(:coords)
2884
+ raise_argument_required_error('astro coordinate area') if !options.has_key?(:coord_areas)
2885
+ super(options)
2886
+ end
2887
+
2888
+ # The coordinate system definition: spatial coordinate frame and reference position;
2889
+ # time frame and reference position; the coordinate flavor; and the planetary ephemeris;
2890
+ # an ID is required, since this is how coordinate elements are associated with their
2891
+ # coordinate systems
2892
+ def coord_sys=(ss)
2893
+ raise_argument_required_error('astro coordinate systems') if !ss
2894
+
2895
+ ss = AstroCoordSystemList.new(ss) if ss.class == Array
2896
+ raise_type_mismatch_error(ss, AstroCoordSystemList)
2897
+
2898
+ @coord_sys = ss
2899
+ end
2900
+
2901
+ # Contains information on time and spatial resolution, errors, and pixelsizes (if fixed);
2902
+ # typical best numbers are expected
2903
+ def coords=(c)
2904
+ raise_argument_required_error('astro coordinate') if !c
2905
+ raise_type_mismatch_error(c, AstroCoords)
2906
+ @coords = c
2907
+ end
2908
+
2909
+ # The coverage area of the resource; the fill factor does not need to be 1.0
2910
+ def coord_areas=(a)
2911
+ raise_argument_required_error('astro coordinate area') if !a
2912
+ raise_type_mismatch_error(a, AstroCoordArea)
2913
+ @coord_areas = a
2914
+ end
2915
+
2916
+ def self.from_xml(xml)
2917
+ root = element_from(xml)
2918
+
2919
+ options = {
2920
+ :coord_sys => xml_to_obj(root, AstroCoordSystem),
2921
+ :coords => xml_to_obj(root, AstroCoords, true, Coords),
2922
+ :coord_areas => xml_to_obj(root, AstroCoordArea, true)
2923
+ }
2924
+
2925
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
2926
+ options[:id] = Id.new(id.value) if id
2927
+
2928
+ self.new(options)
2929
+ end
2930
+ end
2931
+
2932
+ # Type for STC search location
2933
+ class SearchLocationType < StcDescription
2934
+ def initialize(options={})
2935
+ raise_argument_required_error('astro coordinate systems') if !options.has_key?(:coord_sys)
2936
+ raise_argument_required_error('astro coordinate area') if !options.has_key?(:coord_areas)
2937
+ super(options)
2938
+ end
2939
+
2940
+ def coord_sys=(ss)
2941
+ aise_argument_required_error('astro coordinate systems') if !ss
2942
+
2943
+ ss = AstroCoordSystemList.new(ss) if ss.class == Array
2944
+ raise_type_mismatch_error(ss, AstroCoordSystemList)
2945
+
2946
+ @coord_sys = ss
2947
+ end
2948
+
2949
+ def coords=(c)
2950
+ raise_type_mismatch_error(c, AstroCoords) if c
2951
+ @coords = c
2952
+ end
2953
+
2954
+ def coord_areas=(a)
2955
+ raise_argument_required_error('astro coordinate area') if !a
2956
+ raise_type_mismatch_error(a, AstroCoordArea)
2957
+ @coord_areas = a
2958
+ end
2959
+
2960
+ def self.from_xml(xml)
2961
+ root = element_from(xml)
2962
+
2963
+ options = {
2964
+ :coord_sys => xml_to_obj(root, AstroCoordSystem),
2965
+ :coords => xml_to_obj(root, AstroCoords, true, Coords),
2966
+ :coord_areas => xml_to_obj(root, AstroCoordArea, true)
2967
+ }
2968
+
2969
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
2970
+ options[:id] = Id.new(id.value) if id
2971
+
2972
+ self.new(options)
2973
+ end
2974
+ end
2975
+
2976
+ # Type for STC catalog entry description
2977
+ class CatalogEntryLocationType < StcDescription
2978
+ class AstroCoordsList < TypedArray
2979
+ def self.restricted_to; [AstroCoords] end
2980
+ def self.minimum_length; 1 end
2981
+ end
2982
+
2983
+ class AstroCoordAreaList < TypedArray
2984
+ def self.restricted_to; [AstroCoordArea] end
2985
+ end
2986
+
2987
+ def initialize(options={})
2988
+ raise_argument_required_error('astro coordinate systems') if !options.has_key?(:coord_sys)
2989
+ raise_argument_required_error('astro coordinates') if !options.has_key?(:coords)
2990
+ super(options)
2991
+ end
2992
+
2993
+ def coord_sys=(ss)
2994
+ raise_argument_required_error('astro coordinate systems') if !ss
2995
+
2996
+ ss = AstroCoordSystemList.new(ss) if ss.class == Array
2997
+ raise_type_mismatch_error(ss, AstroCoordSystemList)
2998
+
2999
+ @coord_sys = ss
3000
+ end
3001
+
3002
+ def coords=(cs)
3003
+ raise_argument_required_error('astro coordinates') if !cs
3004
+
3005
+ cs = CatalogEntryLocationType::AstroCoordsList.new(cs) if cs.class == Array
3006
+ raise_type_mismatch_error(cs, CatalogEntryLocationType::AstroCoordsList)
3007
+
3008
+ @coords = cs
3009
+ end
3010
+
3011
+ def coord_areas=(as)
3012
+ if as
3013
+ as = CatalogEntryLocationType::AstroCoordAreaList.new(as) if as.class == Array
3014
+ raise_type_mismatch_error(as, CatalogEntryLocationType::AstroCoordAreaList)
3015
+ end
3016
+
3017
+ @coord_areas = as
3018
+ end
3019
+
3020
+ def self.from_xml(xml)
3021
+ root = element_from(xml)
3022
+
3023
+ options = {
3024
+ :coord_sys => xml_to_obj(root, AstroCoordSystem),
3025
+ :coords => xml_to_obj(root, AstroCoords, false, Coords),
3026
+ :coord_areas => xml_to_obj(root, AstroCoordArea)
3027
+ }
3028
+
3029
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
3030
+ options[:id] = Id.new(id.value) if id
3031
+
3032
+ self.new(options)
3033
+ end
3034
+ end
3035
+
3036
+ # Type for an observatory location
3037
+ class ObservatoryLocation < StcDescription
3038
+ def initialize(options={})
3039
+ raise_argument_required_error('astro coordinate systems') if !options.has_key?(:coord_sys)
3040
+ raise_argument_required_error('astro coordinate') if !options.has_key?(:coords)
3041
+ super(options)
3042
+ end
3043
+
3044
+ def coord_sys=(ss)
3045
+ raise_argument_required_error('astro coordinate systems') if !ss
3046
+
3047
+ ss = AstroCoordSystemList.new(ss) if ss.class == Array
3048
+ raise_type_mismatch_error(ss, AstroCoordSystemList)
3049
+
3050
+ @coord_sys = ss
3051
+ end
3052
+
3053
+ def coords=(c)
3054
+ raise_argument_required_error('astro coordinate') if !c
3055
+ raise_type_mismatch_error(c, AstroCoords)
3056
+ @coords = c
3057
+ end
3058
+
3059
+ def coord_areas=(cs)
3060
+ raise ArgumentError, 'astro coordinate areas not applicable'
3061
+ end
3062
+
3063
+ def self.from_xml(xml)
3064
+ root = element_from(xml)
3065
+
3066
+ options = {
3067
+ :coord_sys => xml_to_obj(root, AstroCoordSystem),
3068
+ :coords => xml_to_obj(root, AstroCoords, true, Coords)
3069
+ }
3070
+
3071
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
3072
+ options[:id] = Id.new(id.value) if id
3073
+
3074
+ self.new(options)
3075
+ end
3076
+ end
3077
+
3078
+ # Type for describing the coordinate volume occupied by observational data, as seen from the observatory location
3079
+ class ObservationLocation < StcDescription
3080
+ def initialize(options={})
3081
+ raise_argument_required_error('astro coordinate systems') if !options.has_key?(:coord_sys)
3082
+ raise_argument_required_error('astro coordinate') if !options.has_key?(:coords)
3083
+ raise_argument_required_error('astro coordinate area') if !options.has_key?(:coord_areas)
3084
+ super(options)
3085
+ end
3086
+
3087
+ def coord_sys=(ss)
3088
+ raise_argument_required_error('astro coordinate systems') if !ss
3089
+
3090
+ ss = AstroCoordSystemList.new(ss) if ss.class == Array
3091
+ raise_type_mismatch_error(ss, AstroCoordSystemList)
3092
+
3093
+ @coord_sys = ss
3094
+ end
3095
+
3096
+ def coords=(c)
3097
+ raise_argument_required_error('astro coordinate') if !c
3098
+ raise_type_mismatch_error(c, AstroCoords)
3099
+ @coords = c
3100
+ end
3101
+
3102
+ def coord_areas=(a)
3103
+ raise_argument_required_error('astro coordinate area') if !a
3104
+ raise_type_mismatch_error(a, AstroCoordArea)
3105
+ @coord_areas = a
3106
+ end
3107
+
3108
+ def self.from_xml(xml)
3109
+ root = element_from(xml)
3110
+
3111
+ options = {
3112
+ :coord_sys => xml_to_obj(root, AstroCoordSystem),
3113
+ :coords => xml_to_obj(root, AstroCoords, true, Coords),
3114
+ :coord_areas => xml_to_obj(root, AstroCoordArea, true)
3115
+ }
3116
+
3117
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
3118
+ options[:id] = Id.new(id.value) if id
3119
+
3120
+ self.new(options)
3121
+ end
3122
+ end
3123
+
3124
+ class PixelCoordSystemList < TypedArray
3125
+ def self.restricted_to; [PixelCoordSystem] end
3126
+ end
3127
+
3128
+ class PixelCoordsList < TypedArray
3129
+ def self.restricted_to; [PixelCoords] end
3130
+ end
3131
+
3132
+ # Type to specify a pixel space
3133
+ class PixelSpace < StcDescription
3134
+ def initialize(options={})
3135
+ raise_argument_required_error('pixel coordinate system') if !options.has_key?(:coord_sys)
3136
+ raise_argument_required_error('pixel coordinate area') if !options.has_key?(:coord_areas)
3137
+ super(options)
3138
+ end
3139
+
3140
+ def coord_sys=(s)
3141
+ raise_argument_required_error('pixel coordinate system') if !s
3142
+ raise_type_mismatch_error(s, PixelCoordSystem)
3143
+ @coord_sys = s
3144
+ end
3145
+
3146
+ def coords=(cs)
3147
+ if cs
3148
+ cs = PixelCoordsList.new(cs) if cs.class == Array
3149
+ raise_type_mismatch_error(cs, PixelCoordsList)
3150
+ end
3151
+
3152
+ @coords = cs
3153
+ end
3154
+
3155
+ def coord_areas=(a)
3156
+ raise_argument_required_error('pixel coordinate area') if !a
3157
+ raise_type_mismatch_error(a, PixelCoordArea)
3158
+ @coord_areas = a
3159
+ end
3160
+
3161
+ def self.from_xml(xml)
3162
+ root = element_from(xml)
3163
+
3164
+ options = {
3165
+ :coord_sys => xml_to_obj(root, PixelCoordSystem, true),
3166
+ :coords => xml_to_obj(root, PixelCoords, false, Coords),
3167
+ :coord_areas => xml_to_obj(root, PixelCoordArea, true)
3168
+ }
3169
+
3170
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
3171
+ options[:id] = Id.new(id.value) if id
3172
+
3173
+ self.new(options)
3174
+ end
3175
+ end
3176
+
3177
+ # Type for observational STC metadata.
3178
+ # Describes the spatial and temporal volume covered by an observation.
3179
+ class ObsDataLocationType < StcMetadataType
3180
+ attr_reader :observatory_location, :observation_location, :pixel_space
3181
+
3182
+ def initialize(options={})
3183
+ raise_argument_required_error('observatory location') if !options.has_key?(:observatory_location)
3184
+ raise_argument_required_error('observation location') if !options.has_key?(:observation_location)
3185
+ super(options)
3186
+ end
3187
+
3188
+ # Specifies the location of the observatory during the observation
3189
+ def observatory_location=(l)
3190
+ raise_argument_required_error('observatory location') if !l
3191
+ raise_type_mismatch_error(l, ObservatoryLocation)
3192
+ @observatory_location = l
3193
+ end
3194
+
3195
+ # Describes the spatial and temporal coverage of the observation
3196
+ def observation_location=(l)
3197
+ raise_argument_required_error('observation location') if !l
3198
+ raise_type_mismatch_error(l, ObservationLocation)
3199
+ @observation_location = l
3200
+ end
3201
+
3202
+ # Defines the pixel coordinate system for pixelated data
3203
+ def pixel_space=(s)
3204
+ raise_type_mismatch_error(s, PixelSpace) if s
3205
+ @pixel_space = s
3206
+ end
3207
+
3208
+ def to_xml(name=nil)
3209
+ el = super(name)
3210
+
3211
+ el.add_element(self.observatory_location.to_xml('ObservatoryLocation'))
3212
+ el.add_element(self.observation_location.to_xml('ObservationLocation'))
3213
+ el.add_element(self.pixel_space.to_xml('PixelSpace')) if self.pixel_space
3214
+
3215
+ collapse_namespaces(el)
3216
+ el
3217
+ end
3218
+
3219
+ def self.from_xml(xml)
3220
+ root = element_from(xml)
3221
+
3222
+ options = {
3223
+ :observatory_location => ObservatoryLocation.from_xml(
3224
+ REXML::XPath.first(root, 'x:ObservatoryLocation', {'x' => obj_ns.uri})
3225
+ ),
3226
+ :observation_location => ObservationLocation.from_xml(
3227
+ REXML::XPath.first(root, 'x:ObservationLocation', {'x' => obj_ns.uri})
3228
+ )
3229
+ }
3230
+
3231
+ id = root.attributes.get_attribute_ns(obj_ns.uri, 'ID')
3232
+ options[:id] = id.value if id
3233
+
3234
+ pixel_space = REXML::XPath.first(root, 'x:PixelSpace', {'x' => obj_ns.uri})
3235
+ options[:pixel_space] = PixelSpace.from_xml(pixel_space) if pixel_space
3236
+
3237
+ self.new(options)
3238
+ end
3239
+ end
3240
+
3241
+ # Toplevel: Abstract STCmetadata contains a choice of: ResourceProfile, SearchLocation,
3242
+ # CatalogEntryLocation, or ObservationLocation plus ObservatoryLocation elements
3243
+ module StcMetadata; end
3244
+
3245
+ # Describes the spatial and temporal coverage of a resource
3246
+ class StcResourceProfile < StcResourceProfileType
3247
+ include StcMetadata
3248
+ end
3249
+
3250
+ # Defines the spatial and temporal coordinate space specified by a query
3251
+ class SearchLocation < SearchLocationType
3252
+ include StcMetadata
3253
+ end
3254
+
3255
+ # Describes the spatial and temporal coverage of a catalog (fragment) and contains the
3256
+ # coordinates of the catalog entries; multiple coordinate systems are allowed
3257
+ class CatalogEntryLocation < CatalogEntryLocationType
3258
+ include StcMetadata
3259
+ end
3260
+
3261
+ # Describes the coordinate system used in and coordinate space occupied by a particular
3262
+ # observational dataset; it contains an observation location, an observatory location,
3263
+ # and optionally a pixel coordinate system
3264
+ class ObsDataLocation < ObsDataLocationType
3265
+ include StcMetadata
3266
+ end
3267
+
3268
+ end
3269
+ end
3270
+ end
3271
+ end