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.
- data/Rakefile.rb +107 -224
- data/lib/misc.rb +1 -0
- data/lib/misc/misc.rb +60 -0
- data/lib/misc/propertyfile.rb +31 -0
- data/lib/symphony.rb +1 -0
- data/lib/symphony/symphony.rb +247 -0
- data/lib/voruby.rb +186 -0
- data/lib/voruby/active_votable/active_votable.rb +468 -347
- data/lib/voruby/adql/1.0/adql.rb +2418 -0
- data/lib/voruby/adql/support.rb +2 -0
- data/lib/voruby/misc.rb +351 -0
- data/lib/voruby/misc/connection_monitor.rb +97 -0
- data/lib/voruby/misc/libxml_ext.rb +121 -0
- data/lib/voruby/misc/rexml_ext.rb +223 -0
- data/lib/voruby/resolver/resolver.rb +12 -0
- data/lib/voruby/resolver/sesame.rb +299 -0
- data/lib/voruby/sky_query/sky_query.rb +192 -0
- data/lib/voruby/stc/1.10/coords.rb +2272 -0
- data/lib/voruby/stc/1.10/region.rb +892 -0
- data/lib/voruby/stc/1.10/stc.rb +3271 -0
- data/lib/voruby/stc/1.30/stc.rb +8666 -0
- data/lib/voruby/stc/support.rb +2 -0
- data/lib/voruby/ucd/ucd.rb +173 -0
- data/lib/voruby/voevent/1.1/voevent.rb +1124 -0
- data/lib/voruby/voevent/support.rb +5 -0
- data/lib/voruby/votable/1.0/votable.rb +1807 -0
- data/lib/voruby/votable/1.1/votable.rb +2100 -0
- data/lib/voruby/votable/votable.rb +305 -0
- data/lib/voruby/wesix/wesix.rb +491 -0
- data/lib/voruby/xlink/1.2/xlink.rb +21 -0
- data/test/voruby/active_votable/complex.vot +60 -0
- data/test/voruby/active_votable/error.vot +6 -0
- data/test/voruby/active_votable/large.vot +130040 -0
- data/test/voruby/active_votable/simple1.vot +38 -0
- data/test/voruby/active_votable/simple2.vot +38 -0
- data/test/voruby/active_votable/test.rb +193 -0
- data/test/voruby/adql/1.0/adql-alias.sql +1 -0
- data/test/voruby/adql/1.0/adql-alias.xml +26 -0
- data/test/voruby/adql/1.0/adql-avg.sql +1 -0
- data/test/voruby/adql/1.0/adql-avg.xml +31 -0
- data/test/voruby/adql/1.0/adql-circle.sql +1 -0
- data/test/voruby/adql/1.0/adql-circle.xml +46 -0
- data/test/voruby/adql/1.0/adql-expr.sql +1 -0
- data/test/voruby/adql/1.0/adql-expr.xml +34 -0
- data/test/voruby/adql/1.0/adql-function.sql +1 -0
- data/test/voruby/adql/1.0/adql-function.xml +41 -0
- data/test/voruby/adql/1.0/adql-group.sql +1 -0
- data/test/voruby/adql/1.0/adql-group.xml +51 -0
- data/test/voruby/adql/1.0/adql-having.sql +1 -0
- data/test/voruby/adql/1.0/adql-having.xml +25 -0
- data/test/voruby/adql/1.0/adql-like.sql +1 -0
- data/test/voruby/adql/1.0/adql-like.xml +17 -0
- data/test/voruby/adql/1.0/adql-order.sql +1 -0
- data/test/voruby/adql/1.0/adql-order.xml +37 -0
- data/test/voruby/adql/1.0/adql-simple.sql +1 -0
- data/test/voruby/adql/1.0/adql-simple.xml +12 -0
- data/test/voruby/adql/1.0/adql-top.sql +1 -0
- data/test/voruby/adql/1.0/adql-top.xml +33 -0
- data/test/voruby/adql/1.0/test.rb +2220 -0
- data/test/voruby/misc/test.rb +32 -0
- data/test/voruby/resolver/sesame/test.rb +56 -0
- data/test/voruby/sky_query/test.rb +107 -0
- data/test/voruby/stc/1.10/coords_test.rb +3704 -0
- data/test/voruby/stc/1.10/region_test.rb +993 -0
- data/test/voruby/stc/1.10/stc-catalog-entry-location.xml +112 -0
- data/test/voruby/stc/1.10/stc-obs-data-location.xml +126 -0
- data/test/voruby/stc/1.10/stc-region-circle.xml +5 -0
- data/test/voruby/stc/1.10/stc-region-convex.xml +11 -0
- data/test/voruby/stc/1.10/stc-region-convexhull.xml +5 -0
- data/test/voruby/stc/1.10/stc-region-ellipse.xml +7 -0
- data/test/voruby/stc/1.10/stc-region-intersection.xml +25 -0
- data/test/voruby/stc/1.10/stc-region-negation.xml +7 -0
- data/test/voruby/stc/1.10/stc-region-polygon.xml +13 -0
- data/test/voruby/stc/1.10/stc-region-sector.xml +6 -0
- data/test/voruby/stc/1.10/stc-region-union.xml +25 -0
- data/test/voruby/stc/1.10/stc-resource-profile.xml +60 -0
- data/test/voruby/stc/1.10/stc-search-location.xml +54 -0
- data/test/voruby/stc/1.10/stc_test.rb +4626 -0
- data/test/voruby/stc/1.30/stc-catalog-entry-location.xml +210 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-arecibo.xml +353 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-fits.xml +250 -0
- data/test/voruby/stc/1.30/stc-obs-data-location-xlink.xml +63 -0
- data/test/voruby/stc/1.30/stc-obs-data-location.xml +216 -0
- data/test/voruby/stc/1.30/stc-resource-profile-unusual-ref-pos.xml +39 -0
- data/test/voruby/stc/1.30/stc-resource-profile.xml +129 -0
- data/test/voruby/stc/1.30/stc-search-location-arecibo.xml +86 -0
- data/test/voruby/stc/1.30/stc-search-location.xml +101 -0
- data/test/voruby/stc/1.30/test.rb +6274 -0
- data/test/voruby/ucd/test.rb +48 -0
- data/test/voruby/voevent/1.1/test.rb +812 -0
- data/test/{voevent/voevent_v1_1.xml → voruby/voevent/1.1/voevent.xml} +2 -2
- data/test/voruby/voregistry/0.3/test.rb +137 -0
- data/test/voruby/votable/1.0/test.rb +714 -0
- data/test/voruby/votable/1.0/votable.basic.xml +660 -0
- data/test/voruby/votable/1.0/votable.html +86 -0
- data/test/voruby/votable/1.0/votable.ns.xml +56 -0
- data/test/voruby/votable/1.1/test.rb +785 -0
- data/test/voruby/votable/1.1/votable.basic.xml +38 -0
- data/test/voruby/votable/1.1/votable.html +86 -0
- data/test/voruby/votable/1.1/votable.ns.xml +56 -0
- data/test/voruby/votable/test.rb +15 -0
- data/test/voruby/wesix/test.rb +268 -0
- data/test/voruby/wesix/testr.fits +28 -0
- metadata +234 -247
- data/REQUIREMENTS +0 -6
- data/lib/voruby/active_votable/loader.rb +0 -5
- data/lib/voruby/adql/adql.rb +0 -2787
- data/lib/voruby/adql/ext.rb +0 -14
- data/lib/voruby/adql/loader.rb +0 -6
- data/lib/voruby/adql/operations.rb +0 -54
- data/lib/voruby/adql/parser.rb +0 -160
- data/lib/voruby/adql/transforms.rb +0 -573
- data/lib/voruby/ext.rb +0 -17
- data/lib/voruby/loader.rb +0 -4
- data/lib/voruby/misc/propertyfile.rb +0 -36
- data/lib/voruby/plastic/applications.rb +0 -174
- data/lib/voruby/plastic/constants.rb +0 -30
- data/lib/voruby/plastic/loader.rb +0 -10
- data/lib/voruby/plastic/plastic.rb +0 -1
- data/lib/voruby/resources/conesearch/conesearch.rb +0 -9
- data/lib/voruby/resources/conesearch/conesearch_v0_2.rb +0 -55
- data/lib/voruby/resources/conesearch/conesearch_v0_3.rb +0 -50
- data/lib/voruby/resources/conesearch/conesearch_v1_0.rb +0 -72
- data/lib/voruby/resources/conesearch/loader.rb +0 -4
- data/lib/voruby/resources/loader.rb +0 -50
- data/lib/voruby/resources/nodes.rb +0 -190
- data/lib/voruby/resources/openskynode/loader.rb +0 -4
- data/lib/voruby/resources/openskynode/openskynode.rb +0 -9
- data/lib/voruby/resources/openskynode/openskynode_v0_1.rb +0 -54
- data/lib/voruby/resources/sia/loader.rb +0 -5
- data/lib/voruby/resources/sia/sia.rb +0 -9
- data/lib/voruby/resources/sia/sia_v0_6.rb +0 -90
- data/lib/voruby/resources/sia/sia_v0_7.rb +0 -89
- data/lib/voruby/resources/sia/sia_v1_0.rb +0 -122
- data/lib/voruby/resources/stsci.rb +0 -59
- data/lib/voruby/resources/vodataservice/coverage_v0_2.rb +0 -195
- data/lib/voruby/resources/vodataservice/coverage_v0_3.rb +0 -158
- data/lib/voruby/resources/vodataservice/loader.rb +0 -5
- data/lib/voruby/resources/vodataservice/vodataservice.rb +0 -9
- data/lib/voruby/resources/vodataservice/vodataservice_v0_4.rb +0 -189
- data/lib/voruby/resources/vodataservice/vodataservice_v0_5.rb +0 -163
- data/lib/voruby/resources/vodataservice/vodataservice_v1_0.rb +0 -221
- data/lib/voruby/resources/voregistry/loader.rb +0 -4
- data/lib/voruby/resources/voregistry/voregistry.rb +0 -9
- data/lib/voruby/resources/voregistry/voregistry_v0_2.rb +0 -40
- data/lib/voruby/resources/voregistry/voregistry_v0_3.rb +0 -30
- data/lib/voruby/resources/voregistry/voregistry_v1_0.rb +0 -86
- data/lib/voruby/resources/voresource/loader.rb +0 -17
- data/lib/voruby/resources/voresource/voresource.rb +0 -9
- data/lib/voruby/resources/voresource/voresource_v0_10.rb +0 -327
- data/lib/voruby/resources/voresource/voresource_v0_9.rb +0 -405
- data/lib/voruby/resources/voresource/voresource_v1_0.rb +0 -230
- data/lib/voruby/services/ext.rb +0 -11
- data/lib/voruby/services/gestalt/footprint.rb +0 -95
- data/lib/voruby/services/gestalt/wcs_fixer.rb +0 -105
- data/lib/voruby/services/gestalt/wesix.rb +0 -155
- data/lib/voruby/services/loader.rb +0 -7
- data/lib/voruby/services/registry/registry.rb +0 -53
- data/lib/voruby/services/resolver/resolver.rb +0 -35
- data/lib/voruby/services/schema/schema.rb +0 -644
- data/lib/voruby/sesame/loader.rb +0 -6
- data/lib/voruby/sesame/sesame_v1_0.rb +0 -64
- data/lib/voruby/simple/loader.rb +0 -6
- data/lib/voruby/simple/parameters.rb +0 -196
- data/lib/voruby/simple/sap.rb +0 -446
- data/lib/voruby/spacetime/loader.rb +0 -3
- data/lib/voruby/spacetime/spacetime.rb +0 -607
- data/lib/voruby/stc/coords_v1_20.rb +0 -900
- data/lib/voruby/stc/loader.rb +0 -55
- data/lib/voruby/stc/region_v1_20.rb +0 -274
- data/lib/voruby/stc/stc_v1_20.rb +0 -1196
- data/lib/voruby/util.rb +0 -27
- data/lib/voruby/voevent/loader.rb +0 -7
- data/lib/voruby/voevent/voevent_v1_0.rb +0 -213
- data/lib/voruby/voevent/voevent_v1_1.rb +0 -196
- data/lib/voruby/votables/chandra.rb +0 -373
- data/lib/voruby/votables/data.rb +0 -179
- data/lib/voruby/votables/galex.rb +0 -377
- data/lib/voruby/votables/int.rb +0 -354
- data/lib/voruby/votables/libxml_parser.rb +0 -411
- data/lib/voruby/votables/libxml_votable.rb +0 -67
- data/lib/voruby/votables/loader.rb +0 -10
- data/lib/voruby/votables/meta.rb +0 -763
- data/lib/voruby/votables/misc.rb +0 -51
- data/lib/voruby/votables/nsa.rb +0 -410
- data/lib/voruby/votables/rexml_parser.rb +0 -408
- data/lib/voruby/votables/rexml_votable.rb +0 -67
- data/lib/voruby/votables/sdss.rb +0 -356
- data/lib/voruby/votables/transforms.rb +0 -388
- data/lib/voruby/votables/tree.rb +0 -45
- data/lib/voruby/votables/types.rb +0 -391
- data/lib/voruby/votables/votable.rb +0 -687
- data/test/active_votable/database.yml +0 -6
- data/test/active_votable/test.vot +0 -168492
- data/test/active_votable/unittest.rb +0 -41
- data/test/adql/test1.adql +0 -49
- data/test/adql/test2.adql +0 -51
- data/test/adql/test3.adql +0 -81
- data/test/adql/test4.adql +0 -53
- data/test/adql/test5.adql +0 -55
- data/test/adql/test6.adql +0 -18
- data/test/adql/test7.adql +0 -48
- data/test/adql/unittest.rb +0 -1672
- data/test/plastic/test.rb +0 -44
- data/test/plastic/test.vot +0 -5385
- data/test/plastic/unittest.rb +0 -66
- data/test/resources/conesearch/conesearch_v0_3.xml +0 -31
- data/test/resources/conesearch/conesearch_v1_0.xml +0 -86
- data/test/resources/conesearch/unittest_v0_3.rb +0 -22
- data/test/resources/conesearch/unittest_v1_0.rb +0 -24
- data/test/resources/openskynode/open_sky_node_v0_1.xml +0 -32
- data/test/resources/openskynode/unittest_v0_1.rb +0 -31
- data/test/resources/sia/simple_image_access_v0_7.xml +0 -36
- data/test/resources/sia/simple_image_access_v1_0.xml +0 -122
- data/test/resources/sia/unittest_v0_7.rb +0 -24
- data/test/resources/sia/unittest_v1_0.rb +0 -29
- data/test/resources/stsci.xml +0 -336
- data/test/resources/unittest_stsci.rb +0 -25
- data/test/resources/vodataservice/catalog_service_resource_v1_0.xml +0 -128
- data/test/resources/vodataservice/data_collection_resource_v0_5.xml +0 -54
- data/test/resources/vodataservice/data_collection_resource_v1_0.xml +0 -117
- data/test/resources/vodataservice/data_service_resource_v1_0.xml +0 -115
- data/test/resources/vodataservice/sky_service_resource_v0_10.xml +0 -45
- data/test/resources/vodataservice/table_service_resource_v1_0.xml +0 -122
- data/test/resources/vodataservice/tabular_sky_service_resource_v0_10.xml +0 -60
- data/test/resources/vodataservice/unittest_v0_5.rb +0 -126
- data/test/resources/vodataservice/unittest_v1_0.rb +0 -151
- data/test/resources/voregistry/authority_resource_v0_3.xml +0 -20
- data/test/resources/voregistry/authority_resource_v1_0.xml +0 -82
- data/test/resources/voregistry/registry_service_v0_3.xml +0 -20
- data/test/resources/voregistry/registry_service_v1_0.xml +0 -107
- data/test/resources/voregistry/unittest_v0_3.rb +0 -31
- data/test/resources/voregistry/unittest_v1_0.rb +0 -34
- data/test/resources/voresource/organisation_resource_v1_0.xml +0 -90
- data/test/resources/voresource/resource_organisation_v0_10.xml +0 -22
- data/test/resources/voresource/resource_service_v0_10.xml +0 -19
- data/test/resources/voresource/resource_v0_10.xml +0 -19
- data/test/resources/voresource/resource_v1_0.xml +0 -79
- data/test/resources/voresource/service_resource_v1_0.xml +0 -91
- data/test/resources/voresource/unittest_v0_10.rb +0 -61
- data/test/resources/voresource/unittest_v0_9.rb +0 -4
- data/test/resources/voresource/unittest_v1_0.rb +0 -190
- data/test/services/gestalt/unittest.rb +0 -74
- data/test/services/registry/unittest.rb +0 -34
- data/test/services/resolver/unittest.rb +0 -38
- data/test/simple/unittest.rb +0 -46
- data/test/spacetime/unittest.rb +0 -39
- data/test/stc/catalog_entry_location_v1_20.xml +0 -112
- data/test/stc/obs_data_location_v1_20.xml +0 -108
- data/test/stc/search_location_v1_20.xml +0 -54
- data/test/stc/stc_resource_profile_v1_20.xml +0 -60
- data/test/stc/unittest_v1_20.rb +0 -620
- data/test/voevent/unittest_v1_0.rb +0 -79
- data/test/voevent/unittest_v1_1.rb +0 -70
- data/test/voevent/voevent_v1_0.xml +0 -96
- data/test/votables/test.vot +0 -366
- 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
|