voruby 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. data/Rakefile.rb +107 -224
  2. data/lib/misc.rb +1 -0
  3. data/lib/misc/misc.rb +60 -0
  4. data/lib/misc/propertyfile.rb +31 -0
  5. data/lib/symphony.rb +1 -0
  6. data/lib/symphony/symphony.rb +247 -0
  7. data/lib/voruby.rb +186 -0
  8. data/lib/voruby/active_votable/active_votable.rb +468 -347
  9. data/lib/voruby/adql/1.0/adql.rb +2418 -0
  10. data/lib/voruby/adql/support.rb +2 -0
  11. data/lib/voruby/misc.rb +351 -0
  12. data/lib/voruby/misc/connection_monitor.rb +97 -0
  13. data/lib/voruby/misc/libxml_ext.rb +121 -0
  14. data/lib/voruby/misc/rexml_ext.rb +223 -0
  15. data/lib/voruby/resolver/resolver.rb +12 -0
  16. data/lib/voruby/resolver/sesame.rb +299 -0
  17. data/lib/voruby/sky_query/sky_query.rb +192 -0
  18. data/lib/voruby/stc/1.10/coords.rb +2272 -0
  19. data/lib/voruby/stc/1.10/region.rb +892 -0
  20. data/lib/voruby/stc/1.10/stc.rb +3271 -0
  21. data/lib/voruby/stc/1.30/stc.rb +8666 -0
  22. data/lib/voruby/stc/support.rb +2 -0
  23. data/lib/voruby/ucd/ucd.rb +173 -0
  24. data/lib/voruby/voevent/1.1/voevent.rb +1124 -0
  25. data/lib/voruby/voevent/support.rb +5 -0
  26. data/lib/voruby/votable/1.0/votable.rb +1807 -0
  27. data/lib/voruby/votable/1.1/votable.rb +2100 -0
  28. data/lib/voruby/votable/votable.rb +305 -0
  29. data/lib/voruby/wesix/wesix.rb +491 -0
  30. data/lib/voruby/xlink/1.2/xlink.rb +21 -0
  31. data/test/voruby/active_votable/complex.vot +60 -0
  32. data/test/voruby/active_votable/error.vot +6 -0
  33. data/test/voruby/active_votable/large.vot +130040 -0
  34. data/test/voruby/active_votable/simple1.vot +38 -0
  35. data/test/voruby/active_votable/simple2.vot +38 -0
  36. data/test/voruby/active_votable/test.rb +193 -0
  37. data/test/voruby/adql/1.0/adql-alias.sql +1 -0
  38. data/test/voruby/adql/1.0/adql-alias.xml +26 -0
  39. data/test/voruby/adql/1.0/adql-avg.sql +1 -0
  40. data/test/voruby/adql/1.0/adql-avg.xml +31 -0
  41. data/test/voruby/adql/1.0/adql-circle.sql +1 -0
  42. data/test/voruby/adql/1.0/adql-circle.xml +46 -0
  43. data/test/voruby/adql/1.0/adql-expr.sql +1 -0
  44. data/test/voruby/adql/1.0/adql-expr.xml +34 -0
  45. data/test/voruby/adql/1.0/adql-function.sql +1 -0
  46. data/test/voruby/adql/1.0/adql-function.xml +41 -0
  47. data/test/voruby/adql/1.0/adql-group.sql +1 -0
  48. data/test/voruby/adql/1.0/adql-group.xml +51 -0
  49. data/test/voruby/adql/1.0/adql-having.sql +1 -0
  50. data/test/voruby/adql/1.0/adql-having.xml +25 -0
  51. data/test/voruby/adql/1.0/adql-like.sql +1 -0
  52. data/test/voruby/adql/1.0/adql-like.xml +17 -0
  53. data/test/voruby/adql/1.0/adql-order.sql +1 -0
  54. data/test/voruby/adql/1.0/adql-order.xml +37 -0
  55. data/test/voruby/adql/1.0/adql-simple.sql +1 -0
  56. data/test/voruby/adql/1.0/adql-simple.xml +12 -0
  57. data/test/voruby/adql/1.0/adql-top.sql +1 -0
  58. data/test/voruby/adql/1.0/adql-top.xml +33 -0
  59. data/test/voruby/adql/1.0/test.rb +2220 -0
  60. data/test/voruby/misc/test.rb +32 -0
  61. data/test/voruby/resolver/sesame/test.rb +56 -0
  62. data/test/voruby/sky_query/test.rb +107 -0
  63. data/test/voruby/stc/1.10/coords_test.rb +3704 -0
  64. data/test/voruby/stc/1.10/region_test.rb +993 -0
  65. data/test/voruby/stc/1.10/stc-catalog-entry-location.xml +112 -0
  66. data/test/voruby/stc/1.10/stc-obs-data-location.xml +126 -0
  67. data/test/voruby/stc/1.10/stc-region-circle.xml +5 -0
  68. data/test/voruby/stc/1.10/stc-region-convex.xml +11 -0
  69. data/test/voruby/stc/1.10/stc-region-convexhull.xml +5 -0
  70. data/test/voruby/stc/1.10/stc-region-ellipse.xml +7 -0
  71. data/test/voruby/stc/1.10/stc-region-intersection.xml +25 -0
  72. data/test/voruby/stc/1.10/stc-region-negation.xml +7 -0
  73. data/test/voruby/stc/1.10/stc-region-polygon.xml +13 -0
  74. data/test/voruby/stc/1.10/stc-region-sector.xml +6 -0
  75. data/test/voruby/stc/1.10/stc-region-union.xml +25 -0
  76. data/test/voruby/stc/1.10/stc-resource-profile.xml +60 -0
  77. data/test/voruby/stc/1.10/stc-search-location.xml +54 -0
  78. data/test/voruby/stc/1.10/stc_test.rb +4626 -0
  79. data/test/voruby/stc/1.30/stc-catalog-entry-location.xml +210 -0
  80. data/test/voruby/stc/1.30/stc-obs-data-location-arecibo.xml +353 -0
  81. data/test/voruby/stc/1.30/stc-obs-data-location-fits.xml +250 -0
  82. data/test/voruby/stc/1.30/stc-obs-data-location-xlink.xml +63 -0
  83. data/test/voruby/stc/1.30/stc-obs-data-location.xml +216 -0
  84. data/test/voruby/stc/1.30/stc-resource-profile-unusual-ref-pos.xml +39 -0
  85. data/test/voruby/stc/1.30/stc-resource-profile.xml +129 -0
  86. data/test/voruby/stc/1.30/stc-search-location-arecibo.xml +86 -0
  87. data/test/voruby/stc/1.30/stc-search-location.xml +101 -0
  88. data/test/voruby/stc/1.30/test.rb +6274 -0
  89. data/test/voruby/ucd/test.rb +48 -0
  90. data/test/voruby/voevent/1.1/test.rb +812 -0
  91. data/test/{voevent/voevent_v1_1.xml → voruby/voevent/1.1/voevent.xml} +2 -2
  92. data/test/voruby/voregistry/0.3/test.rb +137 -0
  93. data/test/voruby/votable/1.0/test.rb +714 -0
  94. data/test/voruby/votable/1.0/votable.basic.xml +660 -0
  95. data/test/voruby/votable/1.0/votable.html +86 -0
  96. data/test/voruby/votable/1.0/votable.ns.xml +56 -0
  97. data/test/voruby/votable/1.1/test.rb +785 -0
  98. data/test/voruby/votable/1.1/votable.basic.xml +38 -0
  99. data/test/voruby/votable/1.1/votable.html +86 -0
  100. data/test/voruby/votable/1.1/votable.ns.xml +56 -0
  101. data/test/voruby/votable/test.rb +15 -0
  102. data/test/voruby/wesix/test.rb +268 -0
  103. data/test/voruby/wesix/testr.fits +28 -0
  104. metadata +234 -247
  105. data/REQUIREMENTS +0 -6
  106. data/lib/voruby/active_votable/loader.rb +0 -5
  107. data/lib/voruby/adql/adql.rb +0 -2787
  108. data/lib/voruby/adql/ext.rb +0 -14
  109. data/lib/voruby/adql/loader.rb +0 -6
  110. data/lib/voruby/adql/operations.rb +0 -54
  111. data/lib/voruby/adql/parser.rb +0 -160
  112. data/lib/voruby/adql/transforms.rb +0 -573
  113. data/lib/voruby/ext.rb +0 -17
  114. data/lib/voruby/loader.rb +0 -4
  115. data/lib/voruby/misc/propertyfile.rb +0 -36
  116. data/lib/voruby/plastic/applications.rb +0 -174
  117. data/lib/voruby/plastic/constants.rb +0 -30
  118. data/lib/voruby/plastic/loader.rb +0 -10
  119. data/lib/voruby/plastic/plastic.rb +0 -1
  120. data/lib/voruby/resources/conesearch/conesearch.rb +0 -9
  121. data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +0 -55
  122. data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +0 -50
  123. data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +0 -72
  124. data/lib/voruby/resources/conesearch/loader.rb +0 -4
  125. data/lib/voruby/resources/loader.rb +0 -50
  126. data/lib/voruby/resources/nodes.rb +0 -190
  127. data/lib/voruby/resources/openskynode/loader.rb +0 -4
  128. data/lib/voruby/resources/openskynode/openskynode.rb +0 -9
  129. data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +0 -54
  130. data/lib/voruby/resources/sia/loader.rb +0 -5
  131. data/lib/voruby/resources/sia/sia.rb +0 -9
  132. data/lib/voruby/resources/sia/sia_v0_6.rb +0 -90
  133. data/lib/voruby/resources/sia/sia_v0_7.rb +0 -89
  134. data/lib/voruby/resources/sia/sia_v1_0.rb +0 -122
  135. data/lib/voruby/resources/stsci.rb +0 -59
  136. data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +0 -195
  137. data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +0 -158
  138. data/lib/voruby/resources/vodataservice/loader.rb +0 -5
  139. data/lib/voruby/resources/vodataservice/vodataservice.rb +0 -9
  140. data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +0 -189
  141. data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +0 -163
  142. data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +0 -221
  143. data/lib/voruby/resources/voregistry/loader.rb +0 -4
  144. data/lib/voruby/resources/voregistry/voregistry.rb +0 -9
  145. data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +0 -40
  146. data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +0 -30
  147. data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +0 -86
  148. data/lib/voruby/resources/voresource/loader.rb +0 -17
  149. data/lib/voruby/resources/voresource/voresource.rb +0 -9
  150. data/lib/voruby/resources/voresource/voresource_v0_10.rb +0 -327
  151. data/lib/voruby/resources/voresource/voresource_v0_9.rb +0 -405
  152. data/lib/voruby/resources/voresource/voresource_v1_0.rb +0 -230
  153. data/lib/voruby/services/ext.rb +0 -11
  154. data/lib/voruby/services/gestalt/footprint.rb +0 -95
  155. data/lib/voruby/services/gestalt/wcs_fixer.rb +0 -105
  156. data/lib/voruby/services/gestalt/wesix.rb +0 -155
  157. data/lib/voruby/services/loader.rb +0 -7
  158. data/lib/voruby/services/registry/registry.rb +0 -53
  159. data/lib/voruby/services/resolver/resolver.rb +0 -35
  160. data/lib/voruby/services/schema/schema.rb +0 -644
  161. data/lib/voruby/sesame/loader.rb +0 -6
  162. data/lib/voruby/sesame/sesame_v1_0.rb +0 -64
  163. data/lib/voruby/simple/loader.rb +0 -6
  164. data/lib/voruby/simple/parameters.rb +0 -196
  165. data/lib/voruby/simple/sap.rb +0 -446
  166. data/lib/voruby/spacetime/loader.rb +0 -3
  167. data/lib/voruby/spacetime/spacetime.rb +0 -607
  168. data/lib/voruby/stc/coords_v1_20.rb +0 -900
  169. data/lib/voruby/stc/loader.rb +0 -55
  170. data/lib/voruby/stc/region_v1_20.rb +0 -274
  171. data/lib/voruby/stc/stc_v1_20.rb +0 -1196
  172. data/lib/voruby/util.rb +0 -27
  173. data/lib/voruby/voevent/loader.rb +0 -7
  174. data/lib/voruby/voevent/voevent_v1_0.rb +0 -213
  175. data/lib/voruby/voevent/voevent_v1_1.rb +0 -196
  176. data/lib/voruby/votables/chandra.rb +0 -373
  177. data/lib/voruby/votables/data.rb +0 -179
  178. data/lib/voruby/votables/galex.rb +0 -377
  179. data/lib/voruby/votables/int.rb +0 -354
  180. data/lib/voruby/votables/libxml_parser.rb +0 -411
  181. data/lib/voruby/votables/libxml_votable.rb +0 -67
  182. data/lib/voruby/votables/loader.rb +0 -10
  183. data/lib/voruby/votables/meta.rb +0 -763
  184. data/lib/voruby/votables/misc.rb +0 -51
  185. data/lib/voruby/votables/nsa.rb +0 -410
  186. data/lib/voruby/votables/rexml_parser.rb +0 -408
  187. data/lib/voruby/votables/rexml_votable.rb +0 -67
  188. data/lib/voruby/votables/sdss.rb +0 -356
  189. data/lib/voruby/votables/transforms.rb +0 -388
  190. data/lib/voruby/votables/tree.rb +0 -45
  191. data/lib/voruby/votables/types.rb +0 -391
  192. data/lib/voruby/votables/votable.rb +0 -687
  193. data/test/active_votable/database.yml +0 -6
  194. data/test/active_votable/test.vot +0 -168492
  195. data/test/active_votable/unittest.rb +0 -41
  196. data/test/adql/test1.adql +0 -49
  197. data/test/adql/test2.adql +0 -51
  198. data/test/adql/test3.adql +0 -81
  199. data/test/adql/test4.adql +0 -53
  200. data/test/adql/test5.adql +0 -55
  201. data/test/adql/test6.adql +0 -18
  202. data/test/adql/test7.adql +0 -48
  203. data/test/adql/unittest.rb +0 -1672
  204. data/test/plastic/test.rb +0 -44
  205. data/test/plastic/test.vot +0 -5385
  206. data/test/plastic/unittest.rb +0 -66
  207. data/test/resources/conesearch/conesearch_v0_3.xml +0 -31
  208. data/test/resources/conesearch/conesearch_v1_0.xml +0 -86
  209. data/test/resources/conesearch/unittest_v0_3.rb +0 -22
  210. data/test/resources/conesearch/unittest_v1_0.rb +0 -24
  211. data/test/resources/openskynode/open_sky_node_v0_1.xml +0 -32
  212. data/test/resources/openskynode/unittest_v0_1.rb +0 -31
  213. data/test/resources/sia/simple_image_access_v0_7.xml +0 -36
  214. data/test/resources/sia/simple_image_access_v1_0.xml +0 -122
  215. data/test/resources/sia/unittest_v0_7.rb +0 -24
  216. data/test/resources/sia/unittest_v1_0.rb +0 -29
  217. data/test/resources/stsci.xml +0 -336
  218. data/test/resources/unittest_stsci.rb +0 -25
  219. data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +0 -128
  220. data/test/resources/vodataservice/data_collection_resource_v0_5.xml +0 -54
  221. data/test/resources/vodataservice/data_collection_resource_v1_0.xml +0 -117
  222. data/test/resources/vodataservice/data_service_resource_v1_0.xml +0 -115
  223. data/test/resources/vodataservice/sky_service_resource_v0_10.xml +0 -45
  224. data/test/resources/vodataservice/table_service_resource_v1_0.xml +0 -122
  225. data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +0 -60
  226. data/test/resources/vodataservice/unittest_v0_5.rb +0 -126
  227. data/test/resources/vodataservice/unittest_v1_0.rb +0 -151
  228. data/test/resources/voregistry/authority_resource_v0_3.xml +0 -20
  229. data/test/resources/voregistry/authority_resource_v1_0.xml +0 -82
  230. data/test/resources/voregistry/registry_service_v0_3.xml +0 -20
  231. data/test/resources/voregistry/registry_service_v1_0.xml +0 -107
  232. data/test/resources/voregistry/unittest_v0_3.rb +0 -31
  233. data/test/resources/voregistry/unittest_v1_0.rb +0 -34
  234. data/test/resources/voresource/organisation_resource_v1_0.xml +0 -90
  235. data/test/resources/voresource/resource_organisation_v0_10.xml +0 -22
  236. data/test/resources/voresource/resource_service_v0_10.xml +0 -19
  237. data/test/resources/voresource/resource_v0_10.xml +0 -19
  238. data/test/resources/voresource/resource_v1_0.xml +0 -79
  239. data/test/resources/voresource/service_resource_v1_0.xml +0 -91
  240. data/test/resources/voresource/unittest_v0_10.rb +0 -61
  241. data/test/resources/voresource/unittest_v0_9.rb +0 -4
  242. data/test/resources/voresource/unittest_v1_0.rb +0 -190
  243. data/test/services/gestalt/unittest.rb +0 -74
  244. data/test/services/registry/unittest.rb +0 -34
  245. data/test/services/resolver/unittest.rb +0 -38
  246. data/test/simple/unittest.rb +0 -46
  247. data/test/spacetime/unittest.rb +0 -39
  248. data/test/stc/catalog_entry_location_v1_20.xml +0 -112
  249. data/test/stc/obs_data_location_v1_20.xml +0 -108
  250. data/test/stc/search_location_v1_20.xml +0 -54
  251. data/test/stc/stc_resource_profile_v1_20.xml +0 -60
  252. data/test/stc/unittest_v1_20.rb +0 -620
  253. data/test/voevent/unittest_v1_0.rb +0 -79
  254. data/test/voevent/unittest_v1_1.rb +0 -70
  255. data/test/voevent/voevent_v1_0.xml +0 -96
  256. data/test/votables/test.vot +0 -366
  257. data/test/votables/unittest.rb +0 -54
@@ -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