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,192 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue LoadError; end
|
6
|
+
|
7
|
+
gem 'soap4r'
|
8
|
+
require 'soap/wsdlDriver'
|
9
|
+
|
10
|
+
require 'voruby/votable/1.1/votable'
|
11
|
+
|
12
|
+
module VORuby
|
13
|
+
module SkyQuery
|
14
|
+
class Service
|
15
|
+
attr_accessor :namespace
|
16
|
+
attr_reader :end_point
|
17
|
+
|
18
|
+
# Query the SkyQuery service. A VOTable::V1_1::VOTable is returned.
|
19
|
+
# Service.query('SELECT o.objid, o.ra, o.dec FROM SDSS:PhotoPrimary o WHERE o.type = 3')
|
20
|
+
# This is a convenience method for
|
21
|
+
# Service.new.query('SELECT o.objid, o.ra, o.dec FROM SDSS:PhotoPrimary o WHERE o.type = 3')
|
22
|
+
def self.query(adql, node=nil, options={})
|
23
|
+
self.new(options).query(adql, node)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create a new SkyQuery service instance.
|
27
|
+
# Currently the only valid keys in the <tt>options</tt> hash is <tt>:end_point</tt>
|
28
|
+
# representing the location of the SkyQuery soap service and <tt>:namespace</tt>
|
29
|
+
# representing the namespace of that service. The default is to use OpenSkyQuery
|
30
|
+
# (i.e. end_point = http://openskyquery.net/Sky/SkyPortal/SkyPortal.asmx and
|
31
|
+
# namespace = SkyPortal.ivoa.net)
|
32
|
+
# portal = SkyQuery.new
|
33
|
+
def initialize(options={})
|
34
|
+
self.namespace = options[:namespace] || 'SkyPortal.ivoa.net'
|
35
|
+
self.end_point = options[:end_point] || 'http://openskyquery.net/Sky/SkyPortal/SkyPortal.asmx'
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set the locaton of the SkyPortal webservice.
|
39
|
+
def end_point=(end_point)
|
40
|
+
@end_point = end_point
|
41
|
+
|
42
|
+
# Create the driver.
|
43
|
+
# We don't use the WSDL since we won't expose all possible methods.
|
44
|
+
@portal = SOAP::RPC::Driver.new(self.end_point, self.namespace)
|
45
|
+
#@extractor.wiredump_dev = STDOUT
|
46
|
+
@portal.return_response_as_xml = true # in prep for dumping the result into a VORuby::VOTable
|
47
|
+
|
48
|
+
# Below, we're assuming the namespace prefix for SkyPortal.ivoa.net will always be n1.
|
49
|
+
|
50
|
+
# Queries
|
51
|
+
@portal.add_method_with_soapaction(
|
52
|
+
'SubmitDistributedQuery',
|
53
|
+
"#{self.namespace}/SubmitDistributedQuery",
|
54
|
+
'n1:qry', 'n1:outputType'
|
55
|
+
)
|
56
|
+
@portal.add_method_with_soapaction(
|
57
|
+
'SubmitQuery',
|
58
|
+
"#{self.namespace}/SubmitQuery",
|
59
|
+
'n1:qry', 'n1:node', 'n1:outputType'
|
60
|
+
)
|
61
|
+
|
62
|
+
# Table data
|
63
|
+
@portal.add_method_with_soapaction(
|
64
|
+
'GetTables',
|
65
|
+
"#{self.namespace}/GetTables",
|
66
|
+
'n1:node'
|
67
|
+
)
|
68
|
+
@portal.add_method_with_soapaction(
|
69
|
+
'GetTableInfo',
|
70
|
+
"#{self.namespace}/GetTableInfo",
|
71
|
+
'n1:node', 'n1:table'
|
72
|
+
)
|
73
|
+
|
74
|
+
# Column data
|
75
|
+
@portal.add_method_with_soapaction(
|
76
|
+
'GetMetaColumns',
|
77
|
+
"#{self.namespace}/GetMetaColumns",
|
78
|
+
'n1:node', 'n1:table'
|
79
|
+
)
|
80
|
+
@portal.add_method_with_soapaction(
|
81
|
+
'GetColumnInfo',
|
82
|
+
"#{self.namespace}/GetColumnInfo",
|
83
|
+
'n1:node', 'n1:table', 'n1:column'
|
84
|
+
)
|
85
|
+
@portal.add_method_with_soapaction(
|
86
|
+
'GetColumns',
|
87
|
+
"#{self.namespace}/GetColumns",
|
88
|
+
'n1:node', 'n1:table'
|
89
|
+
)
|
90
|
+
|
91
|
+
# Misc
|
92
|
+
@portal.add_method_with_soapaction(
|
93
|
+
'GetAllSkyNodesVOTable',
|
94
|
+
"#{self.namespace}/GetAllSkyNodesVOTable"
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Find all nodes available from the SkyPortal service.
|
99
|
+
# Returns a VOTable::V1_1::VOTable.
|
100
|
+
def sky_nodes
|
101
|
+
response = @portal.call('GetAllSkyNodesVOTable')
|
102
|
+
parse_votable(response, 'GetAllSkyNodesVOTableResult')
|
103
|
+
end
|
104
|
+
|
105
|
+
# Query the SkyQuery service. A VOTable::V1_1::VOTable is returned.
|
106
|
+
# votable = portal.query('SELECT o.objid, o.ra, o.dec FROM SDSS:PhotoPrimary o WHERE o.type = 3') # typical, distributed query
|
107
|
+
# votable = portal.query('SELECT o.objid, o.ra, o.dec FROM SDSS:PhotoPrimary o WHERE o.type = 3', 'SDSS') # query a particular node (unusual)
|
108
|
+
def query(adql, node=nil)
|
109
|
+
response = node ?
|
110
|
+
@portal.call('SubmitQuery', adql.to_s, node, 'votable') :
|
111
|
+
@portal.call('SubmitDistributedQuery', adql.to_s, 'votable')
|
112
|
+
|
113
|
+
parse_votable(response)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Retrieve the list of tables associated with the specified node.
|
117
|
+
# Returns a list of objects with #name, #description and #rows fields.
|
118
|
+
# tables = portal.tables('SDSS')
|
119
|
+
def tables(node)
|
120
|
+
response = @portal.call('GetTables', node.to_s)
|
121
|
+
XML::Parser.string(response).parse.root.find("//*[local-name()='MetaTable']").collect{ |mt| parse_meta_table(mt) }
|
122
|
+
end
|
123
|
+
|
124
|
+
# Retrieve the metadata associated with the specified table.
|
125
|
+
# Returns an object with #name, #description and #rows fields.
|
126
|
+
# info = portal.table_info('SDSS', 'PhotoPrimary')
|
127
|
+
def table_info(node, table)
|
128
|
+
response = @portal.call('GetTableInfo', node.to_s, table.to_s)
|
129
|
+
xml = XML::Parser.string(response).parse.root.find_first("//*[local-name()='GetTableInfoResult']")
|
130
|
+
parse_meta_table(xml)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Retrieve the metadata associated with the columns of the specified table.
|
134
|
+
# Returns a list of objects with #name, #unit, #description and #ucd fields.
|
135
|
+
# columns = portal.meta_columns('SDSS', 'PhotoPrimary')
|
136
|
+
def meta_columns(node, table)
|
137
|
+
response = @portal.call('GetMetaColumns', node.to_s, table.to_s)
|
138
|
+
XML::Parser.string(response).parse.root.find("//*[local-name()='MetaColumn']").collect{ |mc| parse_meta_column(mc) }
|
139
|
+
end
|
140
|
+
|
141
|
+
# Retrieve the metadata associated with the specified column.
|
142
|
+
# Returns an object with #name, #unit, #description and #ucd fields.
|
143
|
+
# info = portal.column_info('SDSS', 'PhotoPrimary', 'modelMag_i')
|
144
|
+
def column_info(node, table, column)
|
145
|
+
response = @portal.call('GetColumnInfo', node.to_s, table.to_s, column.to_s)
|
146
|
+
xml = XML::Parser.string(response).parse.root.find_first("//*[local-name()='GetColumnInfoResult']")
|
147
|
+
parse_meta_column(xml)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Retrieve the list of columns associated with the specified table.
|
151
|
+
# Returns a list of column names.
|
152
|
+
# column_names = portal.columns('SDSS', 'PhotoPrimary')
|
153
|
+
def columns(node, table)
|
154
|
+
response = @portal.call('GetColumns', node.to_s, table.to_s)
|
155
|
+
XML::Parser.string(response).parse.root.find("//*[local-name()='string']").collect { |c| c.content }
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def parse_meta_table(xml)
|
161
|
+
return nil if !xml.child?
|
162
|
+
|
163
|
+
defn = {}
|
164
|
+
xml.each_child do |child|
|
165
|
+
defn[child.name.downcase.to_sym] = child.name == 'Rows' ? Integer(child.content) : child.content.strip
|
166
|
+
end
|
167
|
+
|
168
|
+
defn.empty? ? nil : OpenStruct.new(defn)
|
169
|
+
end
|
170
|
+
|
171
|
+
def parse_meta_column(xml)
|
172
|
+
return nil if !xml.child?
|
173
|
+
|
174
|
+
defn = {}
|
175
|
+
xml.each_child do |child|
|
176
|
+
defn[child.name.downcase.to_sym] = child.content.strip
|
177
|
+
end
|
178
|
+
|
179
|
+
defn.empty? ? nil : OpenStruct.new(defn)
|
180
|
+
end
|
181
|
+
|
182
|
+
def parse_votable(xml, element='VOTABLE')
|
183
|
+
root = XML::Parser.string(xml).parse.root
|
184
|
+
vot_node = root.find_first("//*[local-name()='#{element}']")
|
185
|
+
raise "Unable to find votable in response: #{root}" if !vot_node
|
186
|
+
|
187
|
+
VORuby::VOTable.from_xml(vot_node)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,2272 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'uri'
|
3
|
+
require 'voruby/stc/support'
|
4
|
+
|
5
|
+
module VORuby
|
6
|
+
module STC
|
7
|
+
module V1_10
|
8
|
+
module Coords
|
9
|
+
include XMLUtilities
|
10
|
+
|
11
|
+
# Basic unit type
|
12
|
+
class Unit < Enumeration; end
|
13
|
+
|
14
|
+
# Time units may be second (s), hour (h: 3600 s), day (d: 86400 s),
|
15
|
+
# Julian year (a, yr: 365.25 d), Julian century (cy: 36525 d), or
|
16
|
+
# empty (i.e., dimensionless) for ISO-8601 format
|
17
|
+
class TimeUnit < Unit
|
18
|
+
def self.choices
|
19
|
+
['s', 'h', 'd', 'a', 'yr', 'cy', '']
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(u='')
|
23
|
+
u ||= ''
|
24
|
+
super(u.to_s)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Coordinate units may be angular (degrees, radians, hours, arcmins, arcsecs),
|
29
|
+
# linear (meters, km, mm, AUs, parsecs, kpc, Mpc, lightyears), or empty
|
30
|
+
# (i.e., dimensionless)
|
31
|
+
class PosUnit < Unit
|
32
|
+
def self.choices
|
33
|
+
[
|
34
|
+
'deg', 'deg deg m', 'rad', 'h', 'arcmin', 'arcsec', 'm', 'km',
|
35
|
+
'mm', 'au', 'pc', 'kpc', 'Mpc', 'lyr', ''
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(u='')
|
40
|
+
u ||= ''
|
41
|
+
super(u.to_s)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Angular coordinate units may be degrees, radians, hours, arcmins, arcsecs
|
46
|
+
class AngleUnit < Unit
|
47
|
+
def self.choices
|
48
|
+
['deg', 'rad', 'h', 'arcmin', 'arcsec']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Velocity units are a posUnitType / velTimeType; the latter may be second,
|
53
|
+
# day, hour, year (a or yr), century, but not empty
|
54
|
+
class VelTimeUnit < Unit
|
55
|
+
def self.choices
|
56
|
+
['s', 'h', 'd', 'a', 'yr', 'cy']
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Spectral units may be frequency (Hz, kHz, MHz, GHz), wavelength (meters,
|
61
|
+
# mm, micron, nm, Angstrom), or energy (eV, keV, MeV, GeV, TeV)
|
62
|
+
class SpectralUnit < Unit
|
63
|
+
def self.choices
|
64
|
+
[
|
65
|
+
'Hz', 'kHz', 'MHz', 'GHz',
|
66
|
+
'm', 'mm', 'micron', 'nm', 'A',
|
67
|
+
'eV', 'keV', 'MeV', 'GeV', 'TeV'
|
68
|
+
]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# The actual time scale used: TT, TAI, UTC, TDB, etc.
|
73
|
+
class TimeScale < Enumeration
|
74
|
+
def self.choices
|
75
|
+
[
|
76
|
+
'TT', 'TDT', 'ET',
|
77
|
+
'TDB', 'TCG', 'TCB',
|
78
|
+
'TAI', 'IAT',
|
79
|
+
'UTC', 'LST', 'LOCAL'
|
80
|
+
]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Substitution group for AbsoluteTime component of AstronTime
|
85
|
+
module AbsoluteTime
|
86
|
+
include SerializableToXml
|
87
|
+
|
88
|
+
def ==(time)
|
89
|
+
self.value == time.value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# ISO8601 time; note: only a limited subset of ISO 8601 is allowed: yyyy-mm-ddThh:mm:ss.sss...
|
94
|
+
class ISOTime
|
95
|
+
include AbsoluteTime
|
96
|
+
|
97
|
+
attr_reader :value
|
98
|
+
|
99
|
+
def initialize(dt)
|
100
|
+
self.value = dt
|
101
|
+
end
|
102
|
+
|
103
|
+
def value=(dt)
|
104
|
+
@value = dt.is_a?(DateTime) ? dt : DateTime.parse(dt.to_s)
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_s
|
108
|
+
self.value.strftime("%FT%T.000")
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_xml
|
112
|
+
el = element()
|
113
|
+
el.text = self.to_s
|
114
|
+
collapse_namespaces(el)
|
115
|
+
el
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.from_xml(xml)
|
119
|
+
ISOTime.new(element_from(xml).text)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# IDREF to an ISO8601 time
|
124
|
+
class ISOTimeRef < IdRef
|
125
|
+
include AbsoluteTime
|
126
|
+
end
|
127
|
+
|
128
|
+
# JD time
|
129
|
+
class JDTime
|
130
|
+
include AbsoluteTime
|
131
|
+
|
132
|
+
attr_reader :value
|
133
|
+
|
134
|
+
def initialize(dt)
|
135
|
+
self.value = dt
|
136
|
+
end
|
137
|
+
|
138
|
+
def value=(dt)
|
139
|
+
@value = Float(dt)
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_s
|
143
|
+
self.value.to_s
|
144
|
+
end
|
145
|
+
|
146
|
+
def to_datetime
|
147
|
+
DateTime.jd(self.value)
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_xml
|
151
|
+
el = element()
|
152
|
+
el.text = self.value.to_s
|
153
|
+
collapse_namespaces(el)
|
154
|
+
el
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.from_xml(xml)
|
158
|
+
JDTime.new(element_from(xml).text)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# IDREF to a JD time
|
163
|
+
class JDTimeRef < IdRef
|
164
|
+
include AbsoluteTime
|
165
|
+
end
|
166
|
+
|
167
|
+
# MJD time (=JD - 2400000.5)
|
168
|
+
class MJDTime
|
169
|
+
include AbsoluteTime
|
170
|
+
|
171
|
+
attr_reader :value
|
172
|
+
|
173
|
+
def initialize(dt)
|
174
|
+
self.value = dt
|
175
|
+
end
|
176
|
+
|
177
|
+
def value=(dt)
|
178
|
+
@value = Float(dt)
|
179
|
+
end
|
180
|
+
|
181
|
+
def to_s
|
182
|
+
self.value.to_s
|
183
|
+
end
|
184
|
+
|
185
|
+
def to_datetime
|
186
|
+
DateTime.jd(DateTime.mjd_to_jd(self.value))
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_xml
|
190
|
+
el = element()
|
191
|
+
el.text = self.value.to_s
|
192
|
+
collapse_namespaces(el)
|
193
|
+
el
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.from_xml(xml)
|
197
|
+
MJDTime.new(element_from(xml).text)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# IDREF to an MJD time
|
202
|
+
class MJDTimeRef < IdRef
|
203
|
+
include AbsoluteTime
|
204
|
+
end
|
205
|
+
|
206
|
+
# A relocatable time origin for simulations
|
207
|
+
class TimeOrigin < Enumeration
|
208
|
+
include AbsoluteTime
|
209
|
+
|
210
|
+
def self.choices; ['RELOCATABLE'] end
|
211
|
+
|
212
|
+
def initialize(to='RELOCATABLE')
|
213
|
+
self.value = to
|
214
|
+
end
|
215
|
+
|
216
|
+
def to_xml
|
217
|
+
el = element()
|
218
|
+
el.text = self.value.to_s
|
219
|
+
collapse_namespaces(el)
|
220
|
+
el
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.from_xml(xml)
|
224
|
+
TimeOrigin.new(element_from(xml).text)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Substitution group: Relative time is elapsed time relative to the absolute reference time component
|
229
|
+
module RelativeTime
|
230
|
+
include SerializableToXml
|
231
|
+
|
232
|
+
def ==(time)
|
233
|
+
self.offset == time.offset and self.unit == time.unit
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Actual elapsed time offset
|
238
|
+
class TimeOffset
|
239
|
+
include RelativeTime
|
240
|
+
|
241
|
+
attr_reader :offset, :unit
|
242
|
+
|
243
|
+
def initialize(offset, unit=TimeUnit.new('s'))
|
244
|
+
self.offset = offset
|
245
|
+
self.unit = unit
|
246
|
+
end
|
247
|
+
|
248
|
+
def offset=(offset)
|
249
|
+
@offset = Float(offset)
|
250
|
+
end
|
251
|
+
|
252
|
+
def unit=(u)
|
253
|
+
@unit = u.is_a?(TimeUnit) ? u : TimeUnit.new(u)
|
254
|
+
end
|
255
|
+
|
256
|
+
def to_s
|
257
|
+
"#{self.offset} #{self.unit}"
|
258
|
+
end
|
259
|
+
|
260
|
+
def to_xml
|
261
|
+
el = element()
|
262
|
+
el.text = self.offset.to_s
|
263
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
|
264
|
+
collapse_namespaces(el)
|
265
|
+
el
|
266
|
+
end
|
267
|
+
|
268
|
+
def self.from_xml(xml)
|
269
|
+
node = element_from(xml)
|
270
|
+
TimeOffset.new(
|
271
|
+
Float(node.text),
|
272
|
+
node.attributes.get_attribute_ns(obj_ns.uri, 'unit').value
|
273
|
+
)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
class TimeOffsetRef < IdRef
|
278
|
+
include RelativeTime
|
279
|
+
|
280
|
+
attr_reader :unit
|
281
|
+
|
282
|
+
def initialize(ref, unit=TimeUnit.new('s'))
|
283
|
+
super(ref)
|
284
|
+
self.unit = unit
|
285
|
+
end
|
286
|
+
|
287
|
+
def unit=(u)
|
288
|
+
@unit = u.is_a?(TimeUnit) ? u : TimeUnit.new(u)
|
289
|
+
end
|
290
|
+
|
291
|
+
def offset; self.value end
|
292
|
+
def offset=(offset); self.value = offset end
|
293
|
+
|
294
|
+
def to_s
|
295
|
+
"#{self.value} #{self.unit}"
|
296
|
+
end
|
297
|
+
|
298
|
+
def to_xml
|
299
|
+
el = element()
|
300
|
+
el.text = self.value.to_s
|
301
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
|
302
|
+
collapse_namespaces(el)
|
303
|
+
el
|
304
|
+
end
|
305
|
+
|
306
|
+
def self.from_xml(xml)
|
307
|
+
node = element_from(xml)
|
308
|
+
TimeOffsetRef.new(
|
309
|
+
node.text,
|
310
|
+
node.attributes.get_attribute_ns(obj_ns.uri, 'unit').value
|
311
|
+
)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# AstronTime is the generalized astronomical time type and consists of two or three elements:
|
316
|
+
# TimeScale, optional relative time offset, and an absolute time (ISO8601 or a decimal JD or MJD;
|
317
|
+
# or it may be an IDREF to one of those three)
|
318
|
+
class AstronTime
|
319
|
+
include SerializableToXml
|
320
|
+
|
321
|
+
attr_reader :timescale, :relative_time, :absolute_time
|
322
|
+
|
323
|
+
def initialize(timescale, absolute_time, relative_time=nil)
|
324
|
+
self.timescale = timescale
|
325
|
+
self.absolute_time = absolute_time
|
326
|
+
self.relative_time = relative_time
|
327
|
+
end
|
328
|
+
|
329
|
+
def timescale=(ts)
|
330
|
+
raise_argument_required_error('timescale') if !ts
|
331
|
+
@timescale = ts.is_a?(TimeScale) ? ts : TimeScale.new(ts)
|
332
|
+
end
|
333
|
+
|
334
|
+
def absolute_time=(at)
|
335
|
+
raise TypeError, "invalid value '#{at}', expected AbsoluteTime" if !at.is_a?(AbsoluteTime)
|
336
|
+
@absolute_time = at
|
337
|
+
end
|
338
|
+
|
339
|
+
def relative_time=(rt)
|
340
|
+
raise TypeError, "invalid value '#{rt}', expected RelativeTime" if rt and !rt.is_a?(RelativeTime)
|
341
|
+
@relative_time = rt
|
342
|
+
end
|
343
|
+
|
344
|
+
def to_xml(name=nil, ns=nil)
|
345
|
+
el = element(name, ns)
|
346
|
+
|
347
|
+
timescale = REXML::Element.new("#{obj_ns.prefix}:Timescale")
|
348
|
+
timescale.text = self.timescale.to_s
|
349
|
+
|
350
|
+
el.add_element(timescale)
|
351
|
+
el.add_element(self.relative_time.to_xml) if self.relative_time
|
352
|
+
el.add_element(self.absolute_time.to_xml)
|
353
|
+
|
354
|
+
collapse_namespaces(el)
|
355
|
+
|
356
|
+
el
|
357
|
+
end
|
358
|
+
|
359
|
+
def self.from_xml(xml)
|
360
|
+
root = element_from(xml)
|
361
|
+
|
362
|
+
options = {
|
363
|
+
:timescale => TimeScale.new(REXML::XPath.first(root, 'x:Timescale', {'x' => obj_ns.uri}).text),
|
364
|
+
:absolute_time => xml_to_obj(root, AbsoluteTime, true)
|
365
|
+
}
|
366
|
+
options[:relative_time] = xml_to_obj(root, RelativeTime, true)
|
367
|
+
|
368
|
+
AstronTime.new(options[:timescale], options[:absolute_time], options[:relative_time])
|
369
|
+
end
|
370
|
+
|
371
|
+
def ==(time)
|
372
|
+
self.timescale == time.timescale and
|
373
|
+
self.absolute_time == time.absolute_time and
|
374
|
+
self.relative_time == time.relative_time
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# For vector coordinates we need arrays of doubles
|
379
|
+
class DoubleArray < TypedArray
|
380
|
+
include SerializableToXml
|
381
|
+
|
382
|
+
def self.restricted_to; [Float] end
|
383
|
+
|
384
|
+
def self.from_xml(xml)
|
385
|
+
self.new(element_from(xml).text.split(' ').collect{ |n| Float(n) })
|
386
|
+
end
|
387
|
+
|
388
|
+
def to_xml(name=nil, ns=nil)
|
389
|
+
el = element(name, ns)
|
390
|
+
el.text = self.to_s
|
391
|
+
collapse_namespaces(el)
|
392
|
+
el
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# A vector of 2 doubles
|
397
|
+
class Double2 < DoubleArray
|
398
|
+
def self.maximum_length; 2 end
|
399
|
+
def self.minimum_length; 2 end
|
400
|
+
end
|
401
|
+
|
402
|
+
# A vector of 3 doubles
|
403
|
+
class Double3 < DoubleArray
|
404
|
+
def self.maximum_length; 3 end
|
405
|
+
def self.minimum_length; 3 end
|
406
|
+
end
|
407
|
+
|
408
|
+
# A vector of 4 doubles
|
409
|
+
class Double4 < DoubleArray
|
410
|
+
def self.maximum_length; 4 end
|
411
|
+
def self.minimum_length; 4 end
|
412
|
+
end
|
413
|
+
|
414
|
+
# A vector of 9 doubles
|
415
|
+
class Double9 < DoubleArray
|
416
|
+
def self.maximum_length; 9 end
|
417
|
+
def self.minimum_length; 9 end
|
418
|
+
end
|
419
|
+
|
420
|
+
# The head element for the CoordinateValue substitution group
|
421
|
+
module CoordValue
|
422
|
+
include SerializableToXml
|
423
|
+
end
|
424
|
+
|
425
|
+
# Substitution group for a scalar coordinate value
|
426
|
+
module CValue
|
427
|
+
include CoordValue
|
428
|
+
|
429
|
+
def to_s
|
430
|
+
self.value.to_s
|
431
|
+
end
|
432
|
+
|
433
|
+
def ==(value)
|
434
|
+
self.value == value.value
|
435
|
+
end
|
436
|
+
|
437
|
+
def to_xml(name=nil, ns=nil)
|
438
|
+
el = element(name, ns)
|
439
|
+
el.text = self.value.to_s
|
440
|
+
collapse_namespaces(el)
|
441
|
+
el
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# double
|
446
|
+
class Value
|
447
|
+
include CValue
|
448
|
+
|
449
|
+
attr_reader :value
|
450
|
+
|
451
|
+
def initialize(value)
|
452
|
+
self.value = value
|
453
|
+
end
|
454
|
+
|
455
|
+
def value=(v)
|
456
|
+
@value = Float(v)
|
457
|
+
end
|
458
|
+
|
459
|
+
def self.from_xml(xml)
|
460
|
+
Value.new(element_from(xml).text)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
# IDREF to a Value
|
465
|
+
class ValueRef < IdRef
|
466
|
+
include CValue
|
467
|
+
end
|
468
|
+
|
469
|
+
# Substitution group for a scalar coordinate error
|
470
|
+
module CError
|
471
|
+
include SerializableToXml
|
472
|
+
|
473
|
+
def to_s
|
474
|
+
self.value.to_s
|
475
|
+
end
|
476
|
+
|
477
|
+
def ==(error)
|
478
|
+
self.value == error.value
|
479
|
+
end
|
480
|
+
|
481
|
+
def to_xml
|
482
|
+
el = element()
|
483
|
+
el.text = self.value.to_s
|
484
|
+
collapse_namespaces(el)
|
485
|
+
el
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
# double
|
490
|
+
class Error
|
491
|
+
include CError
|
492
|
+
|
493
|
+
attr_reader :value
|
494
|
+
|
495
|
+
def initialize(value)
|
496
|
+
self.value = value
|
497
|
+
end
|
498
|
+
|
499
|
+
def value=(v)
|
500
|
+
@value = Float(v)
|
501
|
+
end
|
502
|
+
|
503
|
+
def self.from_xml(xml)
|
504
|
+
Error.new(element_from(xml).text)
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
# IDREF to an Error
|
509
|
+
class ErrorRef < IdRef
|
510
|
+
include CError
|
511
|
+
end
|
512
|
+
|
513
|
+
# Substitution group for a scalar coordinate resolution
|
514
|
+
module CResolution
|
515
|
+
include SerializableToXml
|
516
|
+
|
517
|
+
def to_s
|
518
|
+
self.value.to_s
|
519
|
+
end
|
520
|
+
|
521
|
+
def ==(res)
|
522
|
+
self.value == res.value
|
523
|
+
end
|
524
|
+
|
525
|
+
def to_xml
|
526
|
+
el = element()
|
527
|
+
el.text = self.value.to_s
|
528
|
+
collapse_namespaces(el)
|
529
|
+
el
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
# double
|
534
|
+
class Resolution
|
535
|
+
include CResolution
|
536
|
+
|
537
|
+
attr_reader :value
|
538
|
+
|
539
|
+
def initialize(value)
|
540
|
+
self.value = value
|
541
|
+
end
|
542
|
+
|
543
|
+
def value=(v)
|
544
|
+
@value = Float(v)
|
545
|
+
end
|
546
|
+
|
547
|
+
def self.from_xml(xml)
|
548
|
+
Resolution.new(element_from(xml).text)
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
class ResolutionRef < IdRef
|
553
|
+
include CResolution
|
554
|
+
end
|
555
|
+
|
556
|
+
# Substitution group for a scalar coordinate size
|
557
|
+
module CSize
|
558
|
+
include SerializableToXml
|
559
|
+
|
560
|
+
def to_s
|
561
|
+
self.value.to_s
|
562
|
+
end
|
563
|
+
|
564
|
+
def ==(size)
|
565
|
+
self.value == size.value
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
# double
|
570
|
+
class Size
|
571
|
+
include CSize
|
572
|
+
|
573
|
+
attr_reader :value
|
574
|
+
|
575
|
+
def initialize(value)
|
576
|
+
self.value = value
|
577
|
+
end
|
578
|
+
|
579
|
+
def value=(v)
|
580
|
+
@value = Float(v)
|
581
|
+
end
|
582
|
+
|
583
|
+
def to_xml
|
584
|
+
el = element()
|
585
|
+
el.text = self.value.to_s
|
586
|
+
collapse_namespaces(el)
|
587
|
+
el
|
588
|
+
end
|
589
|
+
|
590
|
+
def self.from_xml(xml)
|
591
|
+
Size.new(element_from(xml).text)
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
# IDREF to a Size
|
596
|
+
class SizeRef < IdRef
|
597
|
+
include CSize
|
598
|
+
end
|
599
|
+
|
600
|
+
# Substitution group for a scalar coordinate pixel size
|
601
|
+
module CPixSize
|
602
|
+
include SerializableToXml
|
603
|
+
|
604
|
+
def to_s
|
605
|
+
self.value.to_s
|
606
|
+
end
|
607
|
+
|
608
|
+
def ==(pixsize)
|
609
|
+
self.value == pixsize.value
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
# double
|
614
|
+
class PixSize
|
615
|
+
include CPixSize
|
616
|
+
|
617
|
+
attr_reader :value
|
618
|
+
|
619
|
+
def initialize(value)
|
620
|
+
self.value = value
|
621
|
+
end
|
622
|
+
|
623
|
+
def value=(v)
|
624
|
+
@value = Float(v)
|
625
|
+
end
|
626
|
+
|
627
|
+
def to_xml
|
628
|
+
el = element()
|
629
|
+
el.text = self.value.to_s
|
630
|
+
collapse_namespaces(el)
|
631
|
+
el
|
632
|
+
end
|
633
|
+
|
634
|
+
def self.from_xml(xml)
|
635
|
+
PixSize.new(element_from(xml).text)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
# IDREF to a PixelSize
|
640
|
+
class PixSizeRef < IdRef
|
641
|
+
include CPixSize
|
642
|
+
end
|
643
|
+
|
644
|
+
# Abstract coordinate type; a concrete Coordinate consists of a Value, Error,
|
645
|
+
# Resolution, Size, and PixSize
|
646
|
+
class CoordinateType
|
647
|
+
include SerializableToXml
|
648
|
+
|
649
|
+
attr_reader :name
|
650
|
+
|
651
|
+
def initialize(options)
|
652
|
+
if options.is_a?(Hash)
|
653
|
+
options.each { |key, value| send("#{key}=", value) }
|
654
|
+
else
|
655
|
+
self.name = options
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
def name=(n)
|
660
|
+
@name = n ? n.to_s : nil
|
661
|
+
end
|
662
|
+
|
663
|
+
def ==(c)
|
664
|
+
self.name == c.name
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
# Generic scalar coordinate type.
|
669
|
+
# Single CError, CResolution, CSize, CPixSize elements indicate
|
670
|
+
# definite values; pairs indicate ranges.
|
671
|
+
class ScalarCoordinateType < CoordinateType
|
672
|
+
attr_reader :value, :error, :resolution, :size, :pix_size
|
673
|
+
|
674
|
+
def initialize(options={})
|
675
|
+
options.each { |key, value| send("#{key}=", value) }
|
676
|
+
end
|
677
|
+
|
678
|
+
def value=(val)
|
679
|
+
raise_type_mismatch_error(val, CValue) if val
|
680
|
+
@value = val
|
681
|
+
end
|
682
|
+
|
683
|
+
def error=(err)
|
684
|
+
if err
|
685
|
+
err = [err] if !err.is_a?(Array)
|
686
|
+
|
687
|
+
if err.size > 0
|
688
|
+
raise ArgumentError, "#{err.size} > maximum length of 2" if err.size > 2
|
689
|
+
err.each { |e| raise_type_mismatch_error(e, CError) if e }
|
690
|
+
@error = err
|
691
|
+
else
|
692
|
+
@error = nil
|
693
|
+
end
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
def resolution=(res)
|
698
|
+
if res
|
699
|
+
res = [res] if !res.is_a?(Array)
|
700
|
+
|
701
|
+
if res.size > 0
|
702
|
+
raise ArgumentError, "#{res.size} > maximum length of 2" if res.size > 2
|
703
|
+
res.each { |r| raise_type_mismatch_error(r, CResolution) if r }
|
704
|
+
@resolution = res
|
705
|
+
else
|
706
|
+
@resolution = nil
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
def size=(sz)
|
712
|
+
if sz
|
713
|
+
sz = [sz] if !sz.is_a?(Array)
|
714
|
+
|
715
|
+
if sz.size > 0
|
716
|
+
raise ArgumentError, "#{sz.size} > maximum length of 2" if sz.size > 2
|
717
|
+
sz.each { |s| raise_type_mismatch_error(s, CSize) if s }
|
718
|
+
@size = sz
|
719
|
+
else
|
720
|
+
@size = nil
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
def pix_size=(psz)
|
726
|
+
if psz
|
727
|
+
psz = [psz] if !psz.is_a?(Array)
|
728
|
+
|
729
|
+
if psz.size > 0
|
730
|
+
raise ArgumentError, "#{psz.size} > maximum length of 2" if psz.size > 2
|
731
|
+
psz.each { |p| raise_type_mismatch_error(p, CPixSize) if p }
|
732
|
+
@pix_size = psz
|
733
|
+
else
|
734
|
+
@pix_size = nil
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
def to_xml(name=nil)
|
739
|
+
el = element(name)
|
740
|
+
|
741
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
742
|
+
name.text = self.name
|
743
|
+
|
744
|
+
el.add_element(name)
|
745
|
+
el.add_element(self.value.to_xml) if self.value
|
746
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
747
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
748
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
749
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
750
|
+
|
751
|
+
collapse_namespaces(el)
|
752
|
+
|
753
|
+
el
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
def ==(sc)
|
758
|
+
super(sc) and
|
759
|
+
self.value == sc.value and
|
760
|
+
self.error == sc.error and
|
761
|
+
self.resolution == sc.resolution and
|
762
|
+
self.size == sc.size and
|
763
|
+
self.pix_size == sc.pix_size
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
# Time coordinate type.
|
768
|
+
# Single CError, CResolution, CSize, CPixSize elements indicate definite values; pairs indicate ranges.
|
769
|
+
class TimeCoordinate < CoordinateType
|
770
|
+
include SerializableToXml
|
771
|
+
|
772
|
+
attr_reader :time_instant, :error, :resolution, :size, :pix_size
|
773
|
+
|
774
|
+
def initialize(options={})
|
775
|
+
options.each { |key, value| send("#{key}=", value) }
|
776
|
+
end
|
777
|
+
|
778
|
+
def time_instant=(ti)
|
779
|
+
raise_type_mismatch_error(ti, AstronTime) if ti
|
780
|
+
@time_instant = ti
|
781
|
+
end
|
782
|
+
|
783
|
+
def error=(err)
|
784
|
+
if err
|
785
|
+
err = [err] if !err.is_a?(Array)
|
786
|
+
|
787
|
+
if err.size > 0
|
788
|
+
raise ArgumentError, "#{err.size} > maximum length of 2" if err.size > 2
|
789
|
+
err.each { |e| raise_type_mismatch_error(e, CError) if e }
|
790
|
+
@error = err
|
791
|
+
else
|
792
|
+
@error = nil
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
797
|
+
def resolution=(res)
|
798
|
+
if res
|
799
|
+
res = [res] if !res.is_a?(Array)
|
800
|
+
|
801
|
+
if res.size > 0
|
802
|
+
raise ArgumentError, "#{res.size} > maximum length of 2" if res.size > 2
|
803
|
+
res.each { |r| raise_type_mismatch_error(r, CResolution) if r }
|
804
|
+
@resolution = res
|
805
|
+
else
|
806
|
+
@resolution = nil
|
807
|
+
end
|
808
|
+
end
|
809
|
+
end
|
810
|
+
|
811
|
+
def size=(sz)
|
812
|
+
if sz
|
813
|
+
sz = [sz] if !sz.is_a?(Array)
|
814
|
+
|
815
|
+
if sz.size > 0
|
816
|
+
raise ArgumentError, "#{sz.size} > maximum length of 2" if sz.size > 2
|
817
|
+
sz.each { |s| raise_type_mismatch_error(s, CSize) if s }
|
818
|
+
@size = sz
|
819
|
+
else
|
820
|
+
@size = nil
|
821
|
+
end
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
def pix_size=(psz)
|
826
|
+
if psz
|
827
|
+
psz = [psz] if !psz.is_a?(Array)
|
828
|
+
|
829
|
+
if psz.size > 0
|
830
|
+
raise ArgumentError, "#{psz.size} > maximum length of 2" if psz.size > 2
|
831
|
+
psz.each { |p| raise_type_mismatch_error(p, CPixSize) if p }
|
832
|
+
@pix_size = psz
|
833
|
+
else
|
834
|
+
@pix_size = nil
|
835
|
+
end
|
836
|
+
end
|
837
|
+
end
|
838
|
+
|
839
|
+
def unit=(u)
|
840
|
+
raise_type_mismatch_error(u, TimeUnit) if u
|
841
|
+
@unit = u
|
842
|
+
end
|
843
|
+
|
844
|
+
def unit
|
845
|
+
@unit || TimeUnit.new('s')
|
846
|
+
end
|
847
|
+
|
848
|
+
def to_xml(name=nil)
|
849
|
+
el = element(name)
|
850
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
851
|
+
|
852
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
853
|
+
name.text = self.name
|
854
|
+
|
855
|
+
el.add_element(name)
|
856
|
+
el.add_element(self.time_instant.to_xml('TimeInstant')) if self.time_instant
|
857
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
858
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
859
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
860
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
861
|
+
|
862
|
+
collapse_namespaces(el)
|
863
|
+
|
864
|
+
el
|
865
|
+
end
|
866
|
+
|
867
|
+
def self.from_xml(xml)
|
868
|
+
root = element_from(xml)
|
869
|
+
|
870
|
+
options = {
|
871
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
872
|
+
}
|
873
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
874
|
+
options[:unit] = TimeUnit.new(unit.value) if unit
|
875
|
+
|
876
|
+
time_instant = REXML::XPath.first(root, 'x:TimeInstant', {'x' => obj_ns.uri})
|
877
|
+
options[:time_instant] = AstronTime.from_xml(time_instant) if time_instant
|
878
|
+
|
879
|
+
options[:error] = xml_to_obj(root, CError)
|
880
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
881
|
+
options[:size] = xml_to_obj(root, CSize)
|
882
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
883
|
+
|
884
|
+
TimeCoordinate.new(options)
|
885
|
+
end
|
886
|
+
|
887
|
+
def ==(tc)
|
888
|
+
super(tc) and
|
889
|
+
self.time_instant == tc.time_instant and
|
890
|
+
self.error == tc.error and
|
891
|
+
self.resolution == tc.resolution and
|
892
|
+
self.size == tc.size and
|
893
|
+
self.pix_size == tc.pix_size and
|
894
|
+
self.unit == tc.unit
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
# 2 doubles with optional position angle
|
899
|
+
class Size2Type < Double2; end
|
900
|
+
|
901
|
+
# Substitution group for a 2-D coordinate value
|
902
|
+
module CValue2
|
903
|
+
include CoordValue
|
904
|
+
end
|
905
|
+
|
906
|
+
# double vector
|
907
|
+
class Value2 < Double2
|
908
|
+
include CValue2
|
909
|
+
end
|
910
|
+
|
911
|
+
# IDREF to a Value2
|
912
|
+
class Value2Ref < IdRef
|
913
|
+
include CValue2
|
914
|
+
end
|
915
|
+
|
916
|
+
# Substitution group for a 2-D coordinate error
|
917
|
+
module CError2; end
|
918
|
+
|
919
|
+
# size2Type Error element
|
920
|
+
class Error2 < Size2Type
|
921
|
+
include CError2
|
922
|
+
end
|
923
|
+
|
924
|
+
# 2x2 matrix Error element
|
925
|
+
class Error2Matrix < Double4
|
926
|
+
include CError2
|
927
|
+
end
|
928
|
+
|
929
|
+
# IDREF to an Error2
|
930
|
+
class Error2Ref < IdRef
|
931
|
+
include CError2
|
932
|
+
end
|
933
|
+
|
934
|
+
# Substitution group for a 2-D coordinate resolution
|
935
|
+
module CResolution2; end
|
936
|
+
|
937
|
+
# size2Type Resolution element
|
938
|
+
class Resolution2 < Size2Type
|
939
|
+
include CResolution2
|
940
|
+
end
|
941
|
+
|
942
|
+
# 2x2 matrix Resolution element
|
943
|
+
class Resolution2Matrix < Double4
|
944
|
+
include CResolution2
|
945
|
+
end
|
946
|
+
|
947
|
+
# IDREF to a Resolution2
|
948
|
+
class Resolution2Ref < IdRef
|
949
|
+
include CResolution2
|
950
|
+
end
|
951
|
+
|
952
|
+
# Substitution group for a 2-D coordinate size
|
953
|
+
module CSize2; end
|
954
|
+
|
955
|
+
# size2Type Size element
|
956
|
+
class Size2 < Size2Type
|
957
|
+
include CSize2
|
958
|
+
end
|
959
|
+
|
960
|
+
# 2x2 matrix Size element
|
961
|
+
class Size2Matrix < Double4
|
962
|
+
include CSize2
|
963
|
+
end
|
964
|
+
|
965
|
+
# IDREF to a Size2
|
966
|
+
class Size2Ref < IdRef
|
967
|
+
include CSize2
|
968
|
+
end
|
969
|
+
|
970
|
+
# Substitution group for a 2-D coordinate pixel size
|
971
|
+
module CPixSize2; end
|
972
|
+
|
973
|
+
# size2Type PixSize element
|
974
|
+
class PixSize2 < Size2Type
|
975
|
+
include CPixSize2
|
976
|
+
end
|
977
|
+
|
978
|
+
# 2x2 matrix PixSize element
|
979
|
+
class PixSize2Matrix < Double4
|
980
|
+
include CPixSize2
|
981
|
+
end
|
982
|
+
|
983
|
+
# IDREF to a PixSize2<
|
984
|
+
class PixSize2Ref < IdRef
|
985
|
+
include CPixSize2
|
986
|
+
end
|
987
|
+
|
988
|
+
# Generic 2-D coordinate type.
|
989
|
+
# Single CError2, CResolution2, CSize2, CPixSize2 elements indicate definite values; pairs indicate ranges.
|
990
|
+
class Vector2Coordinate < CoordinateType
|
991
|
+
attr_reader :value, :error, :resolution, :size, :pix_size
|
992
|
+
|
993
|
+
def initialize(options={})
|
994
|
+
options.each { |key, value| send("#{key}=", value) }
|
995
|
+
end
|
996
|
+
|
997
|
+
def value=(val)
|
998
|
+
raise_type_mismatch_error(val, CValue2) if val
|
999
|
+
@value = val
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def error=(err)
|
1003
|
+
err = [err] if err.class != Array
|
1004
|
+
|
1005
|
+
if err.size > 0
|
1006
|
+
raise ArgumentError, "#{err.size} > maximum length of 2" if err.size > 2
|
1007
|
+
err.each { |e| raise_type_mismatch_error(e, CError2) if e }
|
1008
|
+
@error = err
|
1009
|
+
else
|
1010
|
+
@error = nil
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def resolution=(res)
|
1015
|
+
res = [res] if res.class != Array
|
1016
|
+
|
1017
|
+
if res.size > 0
|
1018
|
+
raise ArgumentError, "#{res.size} > maximum length of 2" if res.size > 2
|
1019
|
+
res.each { |r| raise_type_mismatch_error(r, CResolution2) if r }
|
1020
|
+
@resolution = res
|
1021
|
+
else
|
1022
|
+
@resolution = nil
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
def size=(sz)
|
1027
|
+
sz = [sz] if sz.class != Array
|
1028
|
+
|
1029
|
+
if sz.size > 0
|
1030
|
+
raise ArgumentError, "#{sz.size} > maximum length of 2" if sz.size > 2
|
1031
|
+
sz.each { |s| raise_type_mismatch_error(s, CSize2) if s }
|
1032
|
+
@size = sz
|
1033
|
+
else
|
1034
|
+
@size = nil
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
def pix_size=(psz)
|
1039
|
+
psz = [psz] if psz.class != Array
|
1040
|
+
|
1041
|
+
if psz.size > 0
|
1042
|
+
raise ArgumentError, "#{psz.size} > maximum length of 2" if psz.size > 2
|
1043
|
+
psz.each { |p| raise_type_mismatch_error(p, CPixSize2) if p }
|
1044
|
+
@pix_size = psz
|
1045
|
+
else
|
1046
|
+
@pix_size = nil
|
1047
|
+
end
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
def ==(sc)
|
1051
|
+
super(sc) and
|
1052
|
+
self.value == sc.value and
|
1053
|
+
self.error == sc.error and
|
1054
|
+
self.resolution == sc.resolution and
|
1055
|
+
self.size == sc.size and
|
1056
|
+
self.pix_size == sc.pix_size
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
# 3 doubles with optional position angles
|
1061
|
+
class Size3Type < Double3; end
|
1062
|
+
|
1063
|
+
# Substitution group for a 3-D coordinate value
|
1064
|
+
module CValue3
|
1065
|
+
include CoordValue
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
# Vector of 3 doubles
|
1069
|
+
class Value3 < Double3
|
1070
|
+
include CValue3
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
# IDREF to a Value3
|
1074
|
+
class Value3Ref < IdRef
|
1075
|
+
include CValue3
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
# Substitution group for a 3-D coordinate error
|
1079
|
+
module CError3; end
|
1080
|
+
|
1081
|
+
# Size3 Error element
|
1082
|
+
class Error3 < Size3Type
|
1083
|
+
include CError3
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
# 3x3 matrix Error element
|
1087
|
+
class Error3Matrix < Double9
|
1088
|
+
include CError3
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# IDREF to an Error3
|
1092
|
+
class Error3Ref < IdRef
|
1093
|
+
include CError3
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
# Substitution group for a 3-D coordinate resolution
|
1097
|
+
module CResolution3; end
|
1098
|
+
|
1099
|
+
# size3 Resolution element
|
1100
|
+
class Resolution3 < Size3Type
|
1101
|
+
include CResolution3
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
# IDREF to a Resolution3
|
1105
|
+
class Resolution3Ref < IdRef
|
1106
|
+
include CResolution3
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
# Substitution group for a 3-D coordinate size
|
1110
|
+
module CSize3; end
|
1111
|
+
|
1112
|
+
# size3 Size element
|
1113
|
+
class Size3 < Size3Type
|
1114
|
+
include CSize3
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
# 3x3 matrix Size element
|
1118
|
+
class Size3Matrix < Double9
|
1119
|
+
include CSize3
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
# IDREF to a Size3
|
1123
|
+
class Size3Ref < IdRef
|
1124
|
+
include CSize3
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
# Substitution group for a 3-D coordinate pixel size
|
1128
|
+
module CPixSize3; end
|
1129
|
+
|
1130
|
+
# size3Type PixSize element
|
1131
|
+
class PixSize3 < Size3Type
|
1132
|
+
include CPixSize3
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
# 3x3 matrix PixSize element
|
1136
|
+
class PixSize3Matrix < Double9
|
1137
|
+
include CPixSize3
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
# IDREF to PixSize3
|
1141
|
+
class PixSize3Ref < IdRef
|
1142
|
+
include CPixSize3
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
# Generic 3-D coordinate type.
|
1146
|
+
# Single CError3, CResolution3, CSize3, CPixSize3 elements indicate definite values; pairs indicate ranges
|
1147
|
+
class Vector3Coordinate < CoordinateType
|
1148
|
+
attr_reader :value, :error, :resolution, :size, :pix_size
|
1149
|
+
|
1150
|
+
def initialize(options={})
|
1151
|
+
options.each { |key, value| send("#{key}=", value) }
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
def value=(val)
|
1155
|
+
raise_type_mismatch_error(val, CValue3) if val
|
1156
|
+
@value = val
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def error=(err)
|
1160
|
+
err = [err] if err.class != Array
|
1161
|
+
|
1162
|
+
if err.size > 0
|
1163
|
+
raise ArgumentError, "#{err.size} > maximum length of 2" if err.size > 2
|
1164
|
+
err.each { |e| raise_type_mismatch_error(e, CError3) if e }
|
1165
|
+
@error = err
|
1166
|
+
else
|
1167
|
+
@error = nil
|
1168
|
+
end
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
def resolution=(res)
|
1172
|
+
res = [res] if res.class != Array
|
1173
|
+
|
1174
|
+
if res.size > 0
|
1175
|
+
raise ArgumentError, "#{res.size} > maximum length of 2" if res.size > 2
|
1176
|
+
res.each { |r| raise_type_mismatch_error(r, CResolution3) if r }
|
1177
|
+
@resolution = res
|
1178
|
+
else
|
1179
|
+
@resolution = nil
|
1180
|
+
end
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
def size=(sz)
|
1184
|
+
sz = [sz] if sz.class != Array
|
1185
|
+
|
1186
|
+
if sz.size > 0
|
1187
|
+
raise ArgumentError, "#{sz.size} > maximum length of 2" if sz.size > 2
|
1188
|
+
sz.each { |s| raise_type_mismatch_error(s, CSize3) if s }
|
1189
|
+
@size = sz
|
1190
|
+
else
|
1191
|
+
@size = nil
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def pix_size=(psz)
|
1196
|
+
psz = [psz] if psz.class != Array
|
1197
|
+
|
1198
|
+
if psz.size > 0
|
1199
|
+
raise ArgumentError, "#{psz.size} > maximum length of 2" if psz.size > 2
|
1200
|
+
psz.each { |p| raise_type_mismatch_error(p, CPixSize3) if p }
|
1201
|
+
@pix_size = psz
|
1202
|
+
else
|
1203
|
+
@pix_size = nil
|
1204
|
+
end
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
def ==(sc)
|
1208
|
+
super(sc) and
|
1209
|
+
self.value == sc.value and
|
1210
|
+
self.error == sc.error and
|
1211
|
+
self.resolution == sc.resolution and
|
1212
|
+
self.size == sc.size and
|
1213
|
+
self.pix_size == sc.pix_size
|
1214
|
+
end
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
# Coordinate substitution group
|
1218
|
+
module Coordinate
|
1219
|
+
include SerializableToXml
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
# Generic scalar coordinate element
|
1223
|
+
class ScalarCoordinate < ScalarCoordinateType
|
1224
|
+
include Coordinate
|
1225
|
+
|
1226
|
+
attr_reader :unit
|
1227
|
+
|
1228
|
+
def unit=(u)
|
1229
|
+
@unit = u.to_s
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def ==(c)
|
1233
|
+
super(c) and self.unit == c.unit
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
def to_xml
|
1237
|
+
el = super('ScalarCoordinate')
|
1238
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
1239
|
+
collapse_namespaces(el)
|
1240
|
+
el
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
def self.from_xml(xml)
|
1244
|
+
root = element_from(xml)
|
1245
|
+
|
1246
|
+
options = {
|
1247
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1248
|
+
}
|
1249
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1250
|
+
options[:unit] = unit.value if unit
|
1251
|
+
options[:value] = xml_to_obj(root, CValue, true)
|
1252
|
+
options[:error] = xml_to_obj(root, CError)
|
1253
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
1254
|
+
options[:size] = xml_to_obj(root, CSize)
|
1255
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
1256
|
+
|
1257
|
+
ScalarCoordinate.new(options)
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def ==(c)
|
1261
|
+
super(c) and self.unit == c.unit
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
# Generic string coordinate element
|
1266
|
+
class StringCoordinate < CoordinateType
|
1267
|
+
include Coordinate
|
1268
|
+
|
1269
|
+
attr_reader :value, :unit
|
1270
|
+
|
1271
|
+
def value=(v)
|
1272
|
+
@value = v.to_s
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
def unit=(u)
|
1276
|
+
@unit = u.to_s
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
def ==(c)
|
1280
|
+
super(c) and
|
1281
|
+
self.value == c.value and
|
1282
|
+
self.unit == c.unit
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
def to_xml
|
1286
|
+
el = element()
|
1287
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
1288
|
+
|
1289
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1290
|
+
name.text = self.name
|
1291
|
+
|
1292
|
+
value = REXML::Element.new("#{obj_ns.prefix}:Value")
|
1293
|
+
value.text = self.value
|
1294
|
+
|
1295
|
+
el.add_element(name)
|
1296
|
+
el.add_element(value)
|
1297
|
+
|
1298
|
+
collapse_namespaces(el)
|
1299
|
+
|
1300
|
+
el
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
def self.from_xml(xml)
|
1304
|
+
root = element_from(xml)
|
1305
|
+
|
1306
|
+
options = {
|
1307
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text,
|
1308
|
+
:value => REXML::XPath.first(root, 'x:Value', {'x' => obj_ns.uri}).text
|
1309
|
+
}
|
1310
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1311
|
+
options['unit'] = unit.value if unit
|
1312
|
+
|
1313
|
+
StringCoordinate.new(options)
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
# Generic coordinate element for pixels
|
1318
|
+
class PixelCoordinate < CoordinateType
|
1319
|
+
include Coordinate
|
1320
|
+
|
1321
|
+
attr_reader :value
|
1322
|
+
|
1323
|
+
def value=(v)
|
1324
|
+
@value = Float(v)
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
def ==(c)
|
1328
|
+
super(c) and
|
1329
|
+
self.value == c.value
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
def to_xml
|
1333
|
+
el = element()
|
1334
|
+
|
1335
|
+
if self.name
|
1336
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1337
|
+
name.text = self.name
|
1338
|
+
el.add_element(name)
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
value = REXML::Element.new("#{obj_ns.prefix}:Value")
|
1342
|
+
value.text = self.value.to_s
|
1343
|
+
el.add_element(value)
|
1344
|
+
|
1345
|
+
collapse_namespaces(el)
|
1346
|
+
|
1347
|
+
el
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
def self.from_xml(xml)
|
1351
|
+
root = element_from(xml)
|
1352
|
+
|
1353
|
+
options = {
|
1354
|
+
:value => REXML::XPath.first(root, 'x:Value', {'x' => obj_ns.uri}).text
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
name = REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri})
|
1358
|
+
options[:name] = name.text if name
|
1359
|
+
|
1360
|
+
PixelCoordinate.new(options)
|
1361
|
+
end
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
# Position coordinate substitution group
|
1365
|
+
module Position
|
1366
|
+
include SerializableToXml
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
# 1-D Position coordinate
|
1370
|
+
class Position1D < ScalarCoordinateType
|
1371
|
+
include Position
|
1372
|
+
|
1373
|
+
attr_reader :unit
|
1374
|
+
|
1375
|
+
def initialize(options={})
|
1376
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1377
|
+
super(options)
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
def unit=(u)
|
1381
|
+
raise_argument_required_error('unit') if !u
|
1382
|
+
raise_type_mismatch_error(u, PosUnit)
|
1383
|
+
@unit = u
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
def to_xml
|
1387
|
+
el = element()
|
1388
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
1389
|
+
|
1390
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1391
|
+
name.text = self.name
|
1392
|
+
|
1393
|
+
el.add_element(name)
|
1394
|
+
el.add_element(self.value.to_xml) if self.value
|
1395
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1396
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1397
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1398
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1399
|
+
|
1400
|
+
collapse_namespaces(el)
|
1401
|
+
|
1402
|
+
el
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
def self.from_xml(xml)
|
1406
|
+
root = element_from(xml)
|
1407
|
+
|
1408
|
+
options = {
|
1409
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1410
|
+
}
|
1411
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1412
|
+
options[:unit] = PosUnit.new(unit.value) if unit
|
1413
|
+
options[:value] = xml_to_obj(root, CValue, true)
|
1414
|
+
options[:error] = xml_to_obj(root, CError)
|
1415
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
1416
|
+
options[:size] = xml_to_obj(root, CSize)
|
1417
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
1418
|
+
|
1419
|
+
Position1D.new(options)
|
1420
|
+
end
|
1421
|
+
|
1422
|
+
def ==(p)
|
1423
|
+
super(p) and
|
1424
|
+
self.unit == p.unit
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
# 2-D Position coordinate
|
1429
|
+
class Position2D < Vector2Coordinate
|
1430
|
+
include Position
|
1431
|
+
|
1432
|
+
attr_reader :unit
|
1433
|
+
|
1434
|
+
def initialize(options={})
|
1435
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1436
|
+
super(options)
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
def unit=(u)
|
1440
|
+
raise_argument_required_error('unit') if !u
|
1441
|
+
raise_type_mismatch_error(u, PosUnit)
|
1442
|
+
@unit = u
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
def to_xml
|
1446
|
+
el = element()
|
1447
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
1448
|
+
|
1449
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1450
|
+
name.text = self.name
|
1451
|
+
|
1452
|
+
el.add_element(name)
|
1453
|
+
el.add_element(self.value.to_xml) if self.value
|
1454
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1455
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1456
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1457
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1458
|
+
|
1459
|
+
collapse_namespaces(el)
|
1460
|
+
|
1461
|
+
el
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
def self.from_xml(xml)
|
1465
|
+
root = element_from(xml)
|
1466
|
+
|
1467
|
+
options = {
|
1468
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1469
|
+
}
|
1470
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1471
|
+
options[:unit] = PosUnit.new(unit.value) if unit
|
1472
|
+
options[:value] = xml_to_obj(root, CValue2, true)
|
1473
|
+
options[:error] = xml_to_obj(root, CError2)
|
1474
|
+
options[:resolution] = xml_to_obj(root, CResolution2)
|
1475
|
+
options[:size] = xml_to_obj(root, CSize2)
|
1476
|
+
options[:pix_size] = xml_to_obj(root, CPixSize2)
|
1477
|
+
|
1478
|
+
Position2D.new(options)
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
def ==(p)
|
1482
|
+
super(p) and
|
1483
|
+
self.unit == p.unit
|
1484
|
+
end
|
1485
|
+
end
|
1486
|
+
|
1487
|
+
class Position3D < Vector3Coordinate
|
1488
|
+
include Position
|
1489
|
+
|
1490
|
+
attr_reader :unit
|
1491
|
+
|
1492
|
+
def initialize(options={})
|
1493
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1494
|
+
super(options)
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
def unit=(u)
|
1498
|
+
raise_argument_required_error('unit') if !u
|
1499
|
+
raise_type_mismatch_error(u, PosUnit)
|
1500
|
+
@unit = u
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
def to_xml
|
1504
|
+
el = element()
|
1505
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
1506
|
+
|
1507
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1508
|
+
name.text = self.name
|
1509
|
+
|
1510
|
+
el.add_element(name)
|
1511
|
+
el.add_element(self.value.to_xml) if self.value
|
1512
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1513
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1514
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1515
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1516
|
+
|
1517
|
+
collapse_namespaces(el)
|
1518
|
+
|
1519
|
+
el
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
def self.from_xml(xml)
|
1523
|
+
root = element_from(xml)
|
1524
|
+
|
1525
|
+
options = {
|
1526
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1527
|
+
}
|
1528
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1529
|
+
options[:unit] = PosUnit.new(unit.value) if unit
|
1530
|
+
options[:value] = xml_to_obj(root, CValue3, true)
|
1531
|
+
options[:error] = xml_to_obj(root, CError3)
|
1532
|
+
options[:resolution] = xml_to_obj(root, CResolution3)
|
1533
|
+
options[:size] = xml_to_obj(root, CSize3)
|
1534
|
+
options[:pix_size] = xml_to_obj(root, CPixSize3)
|
1535
|
+
|
1536
|
+
Position3D.new(options)
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
def ==(p)
|
1540
|
+
super(p) and
|
1541
|
+
self.unit == p.unit
|
1542
|
+
end
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
# Velocity coordinate substitution group
|
1546
|
+
module Velocity
|
1547
|
+
include SerializableToXml
|
1548
|
+
|
1549
|
+
attr_reader :unit, :vel_time_unit
|
1550
|
+
|
1551
|
+
def unit=(u)
|
1552
|
+
raise_type_mismatch_error(u, PosUnit)
|
1553
|
+
@unit = u
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
def vel_time_unit=(vtu)
|
1557
|
+
raise_type_mismatch_error(vtu, VelTimeUnit)
|
1558
|
+
@vel_time_unit = vtu
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
def ==(v)
|
1562
|
+
super(v) and
|
1563
|
+
self.unit == v.unit and
|
1564
|
+
self.vel_time_unit == v.vel_time_unit
|
1565
|
+
end
|
1566
|
+
end
|
1567
|
+
|
1568
|
+
# 1-D Velocity coordinate
|
1569
|
+
class Velocity1D < ScalarCoordinateType
|
1570
|
+
include Velocity
|
1571
|
+
|
1572
|
+
def initialize(options={})
|
1573
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1574
|
+
raise_argument_required_error('velocity time unit') if !options.has_key?(:vel_time_unit)
|
1575
|
+
super(options)
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
def to_xml
|
1579
|
+
el = element()
|
1580
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
|
1581
|
+
el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s
|
1582
|
+
|
1583
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1584
|
+
name.text = self.name
|
1585
|
+
|
1586
|
+
el.add_element(name)
|
1587
|
+
el.add_element(self.value.to_xml) if self.value
|
1588
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1589
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1590
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1591
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1592
|
+
|
1593
|
+
collapse_namespaces(el)
|
1594
|
+
|
1595
|
+
el
|
1596
|
+
end
|
1597
|
+
|
1598
|
+
def self.from_xml(xml)
|
1599
|
+
root = element_from(xml)
|
1600
|
+
|
1601
|
+
options = {
|
1602
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1603
|
+
}
|
1604
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1605
|
+
options[:unit] = PosUnit.new(unit.value)
|
1606
|
+
vel_time_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit')
|
1607
|
+
options[:vel_time_unit] = VelTimeUnit.new(vel_time_unit.value)
|
1608
|
+
options[:value] = xml_to_obj(root, CValue, true)
|
1609
|
+
options[:error] = xml_to_obj(root, CError)
|
1610
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
1611
|
+
options[:size] = xml_to_obj(root, CSize)
|
1612
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
1613
|
+
|
1614
|
+
Velocity1D.new(options)
|
1615
|
+
end
|
1616
|
+
end
|
1617
|
+
|
1618
|
+
# 2-D Velocity coordinate
|
1619
|
+
class Velocity2D < Vector2Coordinate
|
1620
|
+
include Velocity
|
1621
|
+
|
1622
|
+
def initialize(options={})
|
1623
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1624
|
+
raise_argument_required_error('velocity time unit') if !options.has_key?(:vel_time_unit)
|
1625
|
+
super(options)
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
def to_xml
|
1629
|
+
el = element()
|
1630
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
|
1631
|
+
el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s
|
1632
|
+
|
1633
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1634
|
+
name.text = self.name
|
1635
|
+
|
1636
|
+
el.add_element(name)
|
1637
|
+
el.add_element(self.value.to_xml) if self.value
|
1638
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1639
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1640
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1641
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1642
|
+
|
1643
|
+
collapse_namespaces(el)
|
1644
|
+
|
1645
|
+
el
|
1646
|
+
end
|
1647
|
+
|
1648
|
+
def self.from_xml(xml)
|
1649
|
+
root = element_from(xml)
|
1650
|
+
|
1651
|
+
options = {
|
1652
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1653
|
+
}
|
1654
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1655
|
+
options[:unit] = PosUnit.new(unit.value)
|
1656
|
+
vel_time_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit')
|
1657
|
+
options[:vel_time_unit] = VelTimeUnit.new(vel_time_unit.value)
|
1658
|
+
options[:value] = xml_to_obj(root, CValue2, true)
|
1659
|
+
options[:error] = xml_to_obj(root, CError2)
|
1660
|
+
options[:resolution] = xml_to_obj(root, CResolution2)
|
1661
|
+
options[:size] = xml_to_obj(root, CSize2)
|
1662
|
+
options[:pix_size] = xml_to_obj(root, CPixSize2)
|
1663
|
+
|
1664
|
+
Velocity2D.new(options)
|
1665
|
+
end
|
1666
|
+
end
|
1667
|
+
|
1668
|
+
# 3-D Velocity coordinate
|
1669
|
+
class Velocity3D < Vector3Coordinate
|
1670
|
+
include Velocity
|
1671
|
+
|
1672
|
+
def initialize(options={})
|
1673
|
+
raise_argument_required_error('unit') if !options.has_key?(:unit)
|
1674
|
+
raise_argument_required_error('velocity time unit') if !options.has_key?(:vel_time_unit)
|
1675
|
+
super(options)
|
1676
|
+
end
|
1677
|
+
|
1678
|
+
def to_xml
|
1679
|
+
el = element()
|
1680
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s
|
1681
|
+
el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s
|
1682
|
+
|
1683
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1684
|
+
name.text = self.name
|
1685
|
+
|
1686
|
+
el.add_element(name)
|
1687
|
+
el.add_element(self.value.to_xml) if self.value
|
1688
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
1689
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
1690
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
1691
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
1692
|
+
|
1693
|
+
collapse_namespaces(el)
|
1694
|
+
|
1695
|
+
el
|
1696
|
+
end
|
1697
|
+
|
1698
|
+
def self.from_xml(xml)
|
1699
|
+
root = element_from(xml)
|
1700
|
+
|
1701
|
+
options = {
|
1702
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1703
|
+
}
|
1704
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
1705
|
+
options[:unit] = PosUnit.new(unit.value)
|
1706
|
+
vel_time_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit')
|
1707
|
+
options[:vel_time_unit] = VelTimeUnit.new(vel_time_unit.value)
|
1708
|
+
options[:value] = xml_to_obj(root, CValue3, true)
|
1709
|
+
options[:error] = xml_to_obj(root, CError3)
|
1710
|
+
options[:resolution] = xml_to_obj(root, CResolution3)
|
1711
|
+
options[:size] = xml_to_obj(root, CSize3)
|
1712
|
+
options[:pix_size] = xml_to_obj(root, CPixSize3)
|
1713
|
+
|
1714
|
+
Velocity3D.new(options)
|
1715
|
+
end
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
# Specifies a FITS file and optionally a specific HDU by HDU number or HDU name
|
1719
|
+
class Fits
|
1720
|
+
include SerializableToXml
|
1721
|
+
|
1722
|
+
attr_reader :uri, :hdu_num, :hdu_name
|
1723
|
+
|
1724
|
+
def initialize(options={})
|
1725
|
+
raise_argument_required_error('URI') if !options.has_key?(:uri)
|
1726
|
+
options.each { |key, value| send("#{key}=", value) }
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
def uri=(u)
|
1730
|
+
@uri = u.is_a?(URI) ? u : URI.parse(u.to_s)
|
1731
|
+
end
|
1732
|
+
|
1733
|
+
def hdu_num=(i)
|
1734
|
+
@hdu_num = Integer(i) if i
|
1735
|
+
end
|
1736
|
+
|
1737
|
+
def hdu_name=(n)
|
1738
|
+
@hdu_name = n.to_s if n
|
1739
|
+
end
|
1740
|
+
|
1741
|
+
def to_xml(name='FITSFile')
|
1742
|
+
el = element(name)
|
1743
|
+
|
1744
|
+
el.text = self.uri.to_s
|
1745
|
+
el.attributes["#{obj_ns.prefix}:hdu_num"] = self.hdu_num.to_s if self.hdu_num
|
1746
|
+
el.attributes["#{obj_ns.prefix}:hdu_name"] = self.hdu_name if self.hdu_name
|
1747
|
+
|
1748
|
+
collapse_namespaces(el)
|
1749
|
+
|
1750
|
+
el
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
def self.from_xml(xml)
|
1754
|
+
root = element_from(xml)
|
1755
|
+
|
1756
|
+
options = {
|
1757
|
+
:uri => URI.parse(root.text)
|
1758
|
+
}
|
1759
|
+
hdu_num = root.attributes.get_attribute_ns(obj_ns.uri, 'hdu_num')
|
1760
|
+
options[:hdu_num] = hdu_num.value.to_i if hdu_num
|
1761
|
+
hdu_name = root.attributes.get_attribute_ns(obj_ns.uri, 'hdu_name')
|
1762
|
+
options[:hdu_name] = hdu_name.value if hdu_name
|
1763
|
+
|
1764
|
+
Fits.new(options)
|
1765
|
+
end
|
1766
|
+
|
1767
|
+
def ==(f)
|
1768
|
+
self.uri == f.uri and
|
1769
|
+
self.hdu_num == f.hdu_num and
|
1770
|
+
self.hdu_name == f.hdu_name
|
1771
|
+
end
|
1772
|
+
end
|
1773
|
+
|
1774
|
+
# Refers coordinate components to specific columns in the FITS file HDU
|
1775
|
+
class CoordFitsColumns
|
1776
|
+
include SerializableToXml
|
1777
|
+
|
1778
|
+
attr_reader :name, :value, :error, :resolution, :size, :pix_size
|
1779
|
+
|
1780
|
+
def initialize(options={})
|
1781
|
+
raise_argument_required_error('name') if !options.has_key?(:name)
|
1782
|
+
options.each { |key, value| send("#{key}=", value) }
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
def name=(n)
|
1786
|
+
raise_argument_required_error('name') if !n
|
1787
|
+
@name = n.to_s
|
1788
|
+
end
|
1789
|
+
|
1790
|
+
# The column name for the coordinate value; comma-separated if multi-dimensional
|
1791
|
+
def value=(v)
|
1792
|
+
@value = v.to_s if v
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
# The column name for the coordinate error; comma-separated if multi-dimensional
|
1796
|
+
def error=(e)
|
1797
|
+
@error = e.to_s if e
|
1798
|
+
end
|
1799
|
+
|
1800
|
+
# The column name for the coordinate resolution; comma-separated if multi-dimensional
|
1801
|
+
def resolution=(r)
|
1802
|
+
@resolution = r.to_s if r
|
1803
|
+
end
|
1804
|
+
|
1805
|
+
# The column name for the coordinate size; comma-separated if multi-dimensional
|
1806
|
+
def size=(s)
|
1807
|
+
@size = s.to_s if s
|
1808
|
+
end
|
1809
|
+
|
1810
|
+
# The column name for the coordinate pixel size; comma-separated if multi-dimensional
|
1811
|
+
def pix_size=(ps)
|
1812
|
+
@pix_size = ps.to_s if ps
|
1813
|
+
end
|
1814
|
+
|
1815
|
+
def to_xml(name)
|
1816
|
+
el = element(name)
|
1817
|
+
|
1818
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
1819
|
+
name.text = self.name
|
1820
|
+
el.add_element(name)
|
1821
|
+
|
1822
|
+
if self.value
|
1823
|
+
value = REXML::Element.new("#{obj_ns.prefix}:Value")
|
1824
|
+
value.text = self.value
|
1825
|
+
el.add_element(value)
|
1826
|
+
end
|
1827
|
+
|
1828
|
+
if self.error
|
1829
|
+
error = REXML::Element.new("#{obj_ns.prefix}:Error")
|
1830
|
+
error.text = self.error
|
1831
|
+
el.add_element(error)
|
1832
|
+
end
|
1833
|
+
|
1834
|
+
if self.resolution
|
1835
|
+
res = REXML::Element.new("#{obj_ns.prefix}:Resolution")
|
1836
|
+
res.text = self.resolution
|
1837
|
+
el.add_element(res)
|
1838
|
+
end
|
1839
|
+
|
1840
|
+
if self.size
|
1841
|
+
size = REXML::Element.new("#{obj_ns.prefix}:Size")
|
1842
|
+
size.text = self.size
|
1843
|
+
el.add_element(size)
|
1844
|
+
end
|
1845
|
+
|
1846
|
+
if self.pix_size
|
1847
|
+
pix_size = REXML::Element.new("#{obj_ns.prefix}:PixSize")
|
1848
|
+
pix_size.text = self.pix_size
|
1849
|
+
el.add_element(pix_size)
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
collapse_namespaces(el)
|
1853
|
+
|
1854
|
+
el
|
1855
|
+
end
|
1856
|
+
|
1857
|
+
def self.from_xml(xml)
|
1858
|
+
root = element_from(xml)
|
1859
|
+
|
1860
|
+
options = {
|
1861
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
value = REXML::XPath.first(root, 'x:Value', {'x' => obj_ns.uri})
|
1865
|
+
options[:value] = value.text if value
|
1866
|
+
|
1867
|
+
error = REXML::XPath.first(root, 'x:Error', {'x' => obj_ns.uri})
|
1868
|
+
options[:error] = error.text if error
|
1869
|
+
|
1870
|
+
resolution = REXML::XPath.first(root, 'x:Resolution', {'x' => obj_ns.uri})
|
1871
|
+
options[:resolution] = resolution.text if resolution
|
1872
|
+
|
1873
|
+
size = REXML::XPath.first(root, 'x:Size', {'x' => obj_ns.uri})
|
1874
|
+
options[:size] = size.text if size
|
1875
|
+
|
1876
|
+
pix_size = REXML::XPath.first(root, 'x:PixSize', {'x' => obj_ns.uri})
|
1877
|
+
options[:pix_size] = pix_size.text if pix_size
|
1878
|
+
|
1879
|
+
CoordFitsColumns.new(options)
|
1880
|
+
end
|
1881
|
+
|
1882
|
+
def ==(c)
|
1883
|
+
self.name == c.name and
|
1884
|
+
self.value == c.value and
|
1885
|
+
self.error == c.error and
|
1886
|
+
self.resolution == c.resolution and
|
1887
|
+
self.size == c.size and
|
1888
|
+
self.pix_size == c.pix_size
|
1889
|
+
end
|
1890
|
+
end
|
1891
|
+
|
1892
|
+
# Coordinate references to a specific FITS file
|
1893
|
+
class AstroCoordsFile
|
1894
|
+
include SerializableToXml
|
1895
|
+
|
1896
|
+
attr_reader :file, :time, :position, :velocity, :spectral, :redshift
|
1897
|
+
|
1898
|
+
def initialize(options={})
|
1899
|
+
raise_argument_required_error('file') if !options.has_key?(:file)
|
1900
|
+
options.each { |key, value| send("#{key}=", value) }
|
1901
|
+
end
|
1902
|
+
|
1903
|
+
def file=(f)
|
1904
|
+
raise_argument_required_error('file') if !f
|
1905
|
+
raise_type_mismatch_error(f, Fits)
|
1906
|
+
@file = f
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
def time=(t)
|
1910
|
+
raise_type_mismatch_error(t, CoordFitsColumns)
|
1911
|
+
@time = t
|
1912
|
+
end
|
1913
|
+
|
1914
|
+
def position=(p)
|
1915
|
+
raise_type_mismatch_error(p, CoordFitsColumns)
|
1916
|
+
@position = p
|
1917
|
+
end
|
1918
|
+
|
1919
|
+
def velocity=(v)
|
1920
|
+
raise_type_mismatch_error(v, CoordFitsColumns)
|
1921
|
+
@velocity = v
|
1922
|
+
end
|
1923
|
+
|
1924
|
+
def spectral=(s)
|
1925
|
+
raise_type_mismatch_error(s, CoordFitsColumns)
|
1926
|
+
@spectral = s
|
1927
|
+
end
|
1928
|
+
|
1929
|
+
def redshift=(r)
|
1930
|
+
raise_type_mismatch_error(r, CoordFitsColumns)
|
1931
|
+
@redshift = r
|
1932
|
+
end
|
1933
|
+
|
1934
|
+
def to_xml(name=nil)
|
1935
|
+
el = element(name)
|
1936
|
+
|
1937
|
+
el.add_element(self.file.to_xml('FITSFile'))
|
1938
|
+
el.add_element(self.time.to_xml('FITSTime')) if self.time
|
1939
|
+
el.add_element(self.position.to_xml('FITSPosition')) if self.position
|
1940
|
+
el.add_element(self.velocity.to_xml('FITSVelocity')) if self.velocity
|
1941
|
+
el.add_element(self.spectral.to_xml('FITSSpectral')) if self.spectral
|
1942
|
+
el.add_element(self.redshift.to_xml('FITSRedshift')) if self.redshift
|
1943
|
+
|
1944
|
+
collapse_namespaces(el)
|
1945
|
+
|
1946
|
+
el
|
1947
|
+
end
|
1948
|
+
|
1949
|
+
def self.from_xml(xml)
|
1950
|
+
root = element_from(xml)
|
1951
|
+
|
1952
|
+
options = {
|
1953
|
+
:file => Fits.from_xml(REXML::XPath.first(root, 'x:FITSFile', {'x' => obj_ns.uri})),
|
1954
|
+
}
|
1955
|
+
|
1956
|
+
time = REXML::XPath.first(root, 'x:FITSTime', {'x' => obj_ns.uri})
|
1957
|
+
options[:time] = CoordFitsColumns.from_xml(time) if time
|
1958
|
+
|
1959
|
+
position = REXML::XPath.first(root, 'x:FITSPosition', {'x' => obj_ns.uri})
|
1960
|
+
options[:position] = CoordFitsColumns.from_xml(position) if position
|
1961
|
+
|
1962
|
+
velocity = REXML::XPath.first(root, 'x:FITSVelocity', {'x' => obj_ns.uri})
|
1963
|
+
options[:velocity] = CoordFitsColumns.from_xml(velocity) if velocity
|
1964
|
+
|
1965
|
+
spectral = REXML::XPath.first(root, 'x:FITSSpectral', {'x' => obj_ns.uri})
|
1966
|
+
options[:spectral] = CoordFitsColumns.from_xml(spectral) if spectral
|
1967
|
+
|
1968
|
+
redshift = REXML::XPath.first(root, 'x:FITSRedshift', {'x' => obj_ns.uri})
|
1969
|
+
options[:redshift] = CoordFitsColumns.from_xml(redshift) if redshift
|
1970
|
+
|
1971
|
+
AstroCoordsFile.new(options)
|
1972
|
+
end
|
1973
|
+
|
1974
|
+
def ==(c)
|
1975
|
+
self.file == c.file and
|
1976
|
+
self.time == c.time and
|
1977
|
+
self.position == c.position and
|
1978
|
+
self.velocity == c.velocity and
|
1979
|
+
self.spectral == c.spectral and
|
1980
|
+
self.redshift == c.redshift
|
1981
|
+
end
|
1982
|
+
end
|
1983
|
+
|
1984
|
+
class ListOfCoordinates < TypedArray
|
1985
|
+
def self.restricted_to; [Coordinate] end
|
1986
|
+
end
|
1987
|
+
|
1988
|
+
class ListOfPixelCoordinates < TypedArray
|
1989
|
+
def self.restricted_to; [PixelCoordinate] end
|
1990
|
+
def self.minimum_length; 1 end
|
1991
|
+
end
|
1992
|
+
|
1993
|
+
# The generic coordsType
|
1994
|
+
class CoordsType
|
1995
|
+
attr_reader :coordinates, :coord_system_id
|
1996
|
+
|
1997
|
+
def initialize(options={})
|
1998
|
+
raise_argument_required_error('coord system id') if !options.has_key?(:coord_system_id)
|
1999
|
+
options.each { |key, value| send("#{key}=", value) }
|
2000
|
+
end
|
2001
|
+
|
2002
|
+
def coordinates=(cs)
|
2003
|
+
cs = ListOfCoordinates.new(cs) if cs.class == Array
|
2004
|
+
raise_type_mismatch_error(cs, ListOfCoordinates) if cs
|
2005
|
+
@coordinates = if cs
|
2006
|
+
cs.size > 0 ? cs : nil
|
2007
|
+
else
|
2008
|
+
nil
|
2009
|
+
end
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
def coord_system_id=(sys)
|
2013
|
+
raise_argument_required_error('coord system id') if !sys
|
2014
|
+
if sys
|
2015
|
+
@coord_system_id = sys.is_a?(IdRef) ? sys : IdRef.new(sys.to_s)
|
2016
|
+
end
|
2017
|
+
end
|
2018
|
+
|
2019
|
+
def ==(c)
|
2020
|
+
self.coord_system_id == c.coord_system_id and
|
2021
|
+
self.coordinates == c.coordinates
|
2022
|
+
end
|
2023
|
+
end
|
2024
|
+
|
2025
|
+
class Spectral < ScalarCoordinateType
|
2026
|
+
include SerializableToXml
|
2027
|
+
|
2028
|
+
attr_reader :unit
|
2029
|
+
|
2030
|
+
def unit=(u)
|
2031
|
+
raise_type_mismatch_error(u, SpectralUnit) if u
|
2032
|
+
@unit = u
|
2033
|
+
end
|
2034
|
+
|
2035
|
+
def to_xml
|
2036
|
+
el = element()
|
2037
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
2038
|
+
|
2039
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
2040
|
+
name.text = self.name
|
2041
|
+
|
2042
|
+
el.add_element(name)
|
2043
|
+
el.add_element(self.value.to_xml) if self.value
|
2044
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
2045
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
2046
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
2047
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
2048
|
+
|
2049
|
+
collapse_namespaces(el)
|
2050
|
+
|
2051
|
+
el
|
2052
|
+
end
|
2053
|
+
|
2054
|
+
def self.from_xml(xml)
|
2055
|
+
root = element_from(xml)
|
2056
|
+
|
2057
|
+
options = {
|
2058
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
2059
|
+
}
|
2060
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
2061
|
+
options[:unit] = SpectralUnit.new(unit.value) if unit
|
2062
|
+
options[:value] = xml_to_obj(root, CValue, true)
|
2063
|
+
options[:error] = xml_to_obj(root, CError)
|
2064
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
2065
|
+
options[:size] = xml_to_obj(root, CSize)
|
2066
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
2067
|
+
|
2068
|
+
Spectral.new(options)
|
2069
|
+
end
|
2070
|
+
|
2071
|
+
def ==(c)
|
2072
|
+
super(c) and self.unit == c.unit
|
2073
|
+
end
|
2074
|
+
end
|
2075
|
+
|
2076
|
+
class Redshift < ScalarCoordinateType
|
2077
|
+
include SerializableToXml
|
2078
|
+
|
2079
|
+
attr_reader :unit, :vel_time_unit
|
2080
|
+
|
2081
|
+
def unit=(u)
|
2082
|
+
raise_type_mismatch_error(u, PosUnit) if u
|
2083
|
+
@unit = u
|
2084
|
+
end
|
2085
|
+
|
2086
|
+
def vel_time_unit=(vtu)
|
2087
|
+
raise_type_mismatch_error(vtu, VelTimeUnit) if vtu
|
2088
|
+
@vel_time_unit = vtu
|
2089
|
+
end
|
2090
|
+
|
2091
|
+
def to_xml
|
2092
|
+
el = element()
|
2093
|
+
el.attributes["#{obj_ns.prefix}:unit"] = self.unit.to_s if self.unit
|
2094
|
+
el.attributes["#{obj_ns.prefix}:vel_time_unit"] = self.vel_time_unit.to_s if self.vel_time_unit
|
2095
|
+
|
2096
|
+
name = REXML::Element.new("#{obj_ns.prefix}:Name")
|
2097
|
+
name.text = self.name
|
2098
|
+
|
2099
|
+
el.add_element(name)
|
2100
|
+
el.add_element(self.value.to_xml) if self.value
|
2101
|
+
self.error.each { |e| el.add_element(e.to_xml) } if self.error
|
2102
|
+
self.resolution.each { |r| el.add_element(r.to_xml) } if self.resolution
|
2103
|
+
self.size.each { |s| el.add_element(s.to_xml) } if self.size
|
2104
|
+
self.pix_size.each { |p| el.add_element(p.to_xml) } if self.pix_size
|
2105
|
+
|
2106
|
+
collapse_namespaces(el)
|
2107
|
+
|
2108
|
+
el
|
2109
|
+
end
|
2110
|
+
|
2111
|
+
def self.from_xml(xml)
|
2112
|
+
root = element_from(xml)
|
2113
|
+
|
2114
|
+
options = {
|
2115
|
+
:name => REXML::XPath.first(root, 'x:Name', {'x' => obj_ns.uri}).text
|
2116
|
+
}
|
2117
|
+
unit = root.attributes.get_attribute_ns(obj_ns.uri, 'unit')
|
2118
|
+
options[:unit] = PosUnit.new(unit.value) if unit
|
2119
|
+
vel_time_unit = root.attributes.get_attribute_ns(obj_ns.uri, 'vel_time_unit')
|
2120
|
+
options[:vel_time_unit] = VelTimeUnit.new(vel_time_unit.value) if vel_time_unit
|
2121
|
+
options[:value] = xml_to_obj(root, CValue, true)
|
2122
|
+
options[:error] = xml_to_obj(root, CError)
|
2123
|
+
options[:resolution] = xml_to_obj(root, CResolution)
|
2124
|
+
options[:size] = xml_to_obj(root, CSize)
|
2125
|
+
options[:pix_size] = xml_to_obj(root, CPixSize)
|
2126
|
+
|
2127
|
+
Redshift.new(options)
|
2128
|
+
end
|
2129
|
+
|
2130
|
+
def ==(c)
|
2131
|
+
super(c) and
|
2132
|
+
self.unit == c.unit and
|
2133
|
+
self.vel_time_unit == c.vel_time_unit
|
2134
|
+
end
|
2135
|
+
end
|
2136
|
+
|
2137
|
+
# The astronomical (STC) coordsType
|
2138
|
+
class AstroCoordsType < CoordsType
|
2139
|
+
attr_reader :time, :position, :velocity, :spectral, :redshift, :coord_file
|
2140
|
+
|
2141
|
+
def time=(t)
|
2142
|
+
raise_type_mismatch_error(t, TimeCoordinate) if t
|
2143
|
+
@time = t
|
2144
|
+
end
|
2145
|
+
|
2146
|
+
def position=(p)
|
2147
|
+
raise_type_mismatch_error(p, Position) if p
|
2148
|
+
@position = p
|
2149
|
+
end
|
2150
|
+
|
2151
|
+
def velocity=(v)
|
2152
|
+
raise_type_mismatch_error(v, Velocity) if v
|
2153
|
+
@velocity = v
|
2154
|
+
end
|
2155
|
+
|
2156
|
+
def spectral=(s)
|
2157
|
+
raise_type_mismatch_error(s, Spectral) if s
|
2158
|
+
@spectral = s
|
2159
|
+
end
|
2160
|
+
|
2161
|
+
def redshift=(r)
|
2162
|
+
raise_type_mismatch_error(r, Redshift) if r
|
2163
|
+
@redshift = r
|
2164
|
+
end
|
2165
|
+
|
2166
|
+
# Some or all coordinate values may be given in file
|
2167
|
+
def coord_file=(c)
|
2168
|
+
raise_type_mismatch_error(c, AstroCoordsFile) if c
|
2169
|
+
@coord_file = c
|
2170
|
+
end
|
2171
|
+
|
2172
|
+
def ==(c)
|
2173
|
+
super(c) and
|
2174
|
+
self.time == c.time and
|
2175
|
+
self.position == c.position and
|
2176
|
+
self.velocity == c.velocity and
|
2177
|
+
self.spectral == c.spectral and
|
2178
|
+
self.redshift == c.redshift and
|
2179
|
+
self.coord_file == c.coord_file
|
2180
|
+
end
|
2181
|
+
end
|
2182
|
+
|
2183
|
+
# The pixel coordinates type
|
2184
|
+
class PixelCoordsType < CoordsType
|
2185
|
+
attr_reader :coordinates
|
2186
|
+
|
2187
|
+
def coordinates=(cs)
|
2188
|
+
cs = ListOfPixelCoordinates.new(cs) if cs.class == Array
|
2189
|
+
raise_type_mismatch_error(cs, ListOfPixelCoordinates) if cs
|
2190
|
+
@coordinates = cs
|
2191
|
+
end
|
2192
|
+
end
|
2193
|
+
|
2194
|
+
# Head element of Coords group (not abstract)
|
2195
|
+
module Coords
|
2196
|
+
include SerializableToXml
|
2197
|
+
end
|
2198
|
+
|
2199
|
+
# The coordinate element consists either of a coordinate file or a sequence of time element, spatial coordinate element,
|
2200
|
+
# velocity element, and redshift element; the spatial and velocity elements may be scalar or vector; it needs to refer
|
2201
|
+
# to a coordinate system
|
2202
|
+
class AstroCoords < AstroCoordsType
|
2203
|
+
include Coords
|
2204
|
+
|
2205
|
+
def to_xml(name=nil, ns=nil)
|
2206
|
+
el = element(name, ns)
|
2207
|
+
el.attributes["#{obj_ns.prefix}:coord_system_id"] = self.coord_system_id.to_s
|
2208
|
+
|
2209
|
+
self.coordinates.each { |c| el.add_element(c.to_xml) } if self.coordinates
|
2210
|
+
el.add_element(self.time.to_xml('Time')) if self.time
|
2211
|
+
el.add_element(self.position.to_xml) if self.position
|
2212
|
+
el.add_element(self.velocity.to_xml) if self.velocity
|
2213
|
+
el.add_element(self.spectral.to_xml) if self.spectral
|
2214
|
+
el.add_element(self.redshift.to_xml) if self.redshift
|
2215
|
+
el.add_element(self.coord_file.to_xml('CoordFile')) if self.coord_file
|
2216
|
+
|
2217
|
+
collapse_namespaces(el)
|
2218
|
+
|
2219
|
+
el
|
2220
|
+
end
|
2221
|
+
|
2222
|
+
def self.from_xml(xml)
|
2223
|
+
root = element_from(xml)
|
2224
|
+
|
2225
|
+
options = {
|
2226
|
+
:coord_system_id => IdRef.new(root.attributes.get_attribute_ns(obj_ns.uri, 'coord_system_id').value),
|
2227
|
+
}
|
2228
|
+
options[:coordinates] = xml_to_obj(root, Coordinate)
|
2229
|
+
time = REXML::XPath.first(root, 'x:Time', {'x' => obj_ns.uri})
|
2230
|
+
options[:time] = TimeCoordinate.from_xml(time) if time
|
2231
|
+
options[:position] = xml_to_obj(root, Position, true)
|
2232
|
+
options[:velocity] = xml_to_obj(root, Velocity, true)
|
2233
|
+
options[:spectral] = xml_to_obj(root, Spectral, true)
|
2234
|
+
options[:redshift] = xml_to_obj(root, Redshift, true)
|
2235
|
+
coord_file = REXML::XPath.first(root, 'x:CoordFile', {'x' => obj_ns.uri})
|
2236
|
+
options[:coord_file] = AstroCoordsFile.from_xml(coord_file) if coord_file
|
2237
|
+
|
2238
|
+
AstroCoords.new(options)
|
2239
|
+
end
|
2240
|
+
end
|
2241
|
+
|
2242
|
+
# Contains pixel coordinates
|
2243
|
+
class PixelCoords < PixelCoordsType
|
2244
|
+
include Coords
|
2245
|
+
|
2246
|
+
def to_xml
|
2247
|
+
el = element()
|
2248
|
+
el.attributes["#{obj_ns.prefix}:coord_system_id"] = self.coord_system_id.to_s
|
2249
|
+
|
2250
|
+
self.coordinates.each { |c| el.add_element(c.to_xml) } if self.coordinates
|
2251
|
+
|
2252
|
+
collapse_namespaces(el)
|
2253
|
+
|
2254
|
+
el
|
2255
|
+
end
|
2256
|
+
|
2257
|
+
def self.from_xml(xml)
|
2258
|
+
root = element_from(xml)
|
2259
|
+
|
2260
|
+
options = {
|
2261
|
+
:coord_system_id => IdRef.new(root.attributes.get_attribute_ns(obj_ns.uri, 'coord_system_id').value)
|
2262
|
+
}
|
2263
|
+
options[:coordinates] = xml_to_obj(root, PixelCoordinate)
|
2264
|
+
|
2265
|
+
PixelCoords.new(options)
|
2266
|
+
end
|
2267
|
+
end
|
2268
|
+
|
2269
|
+
end
|
2270
|
+
end
|
2271
|
+
end
|
2272
|
+
end
|