schleyfox-rgeo 0.2.5
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/History.rdoc +199 -0
- data/README.rdoc +172 -0
- data/Spatial_Programming_With_RGeo.rdoc +440 -0
- data/Version +1 -0
- data/ext/geos_c_impl/extconf.rb +84 -0
- data/ext/geos_c_impl/factory.c +468 -0
- data/ext/geos_c_impl/factory.h +224 -0
- data/ext/geos_c_impl/geometry.c +705 -0
- data/ext/geos_c_impl/geometry.h +55 -0
- data/ext/geos_c_impl/geometry_collection.c +482 -0
- data/ext/geos_c_impl/geometry_collection.h +69 -0
- data/ext/geos_c_impl/line_string.c +509 -0
- data/ext/geos_c_impl/line_string.h +64 -0
- data/ext/geos_c_impl/main.c +70 -0
- data/ext/geos_c_impl/point.c +193 -0
- data/ext/geos_c_impl/point.h +62 -0
- data/ext/geos_c_impl/polygon.c +265 -0
- data/ext/geos_c_impl/polygon.h +66 -0
- data/ext/geos_c_impl/preface.h +50 -0
- data/ext/proj4_c_impl/extconf.rb +88 -0
- data/ext/proj4_c_impl/main.c +271 -0
- data/lib/rgeo.rb +124 -0
- data/lib/rgeo/cartesian.rb +60 -0
- data/lib/rgeo/cartesian/analysis.rb +118 -0
- data/lib/rgeo/cartesian/bounding_box.rb +337 -0
- data/lib/rgeo/cartesian/calculations.rb +161 -0
- data/lib/rgeo/cartesian/factory.rb +209 -0
- data/lib/rgeo/cartesian/feature_classes.rb +173 -0
- data/lib/rgeo/cartesian/feature_methods.rb +106 -0
- data/lib/rgeo/cartesian/interface.rb +150 -0
- data/lib/rgeo/coord_sys.rb +79 -0
- data/lib/rgeo/coord_sys/cs/entities.rb +1524 -0
- data/lib/rgeo/coord_sys/cs/factories.rb +208 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +308 -0
- data/lib/rgeo/coord_sys/proj4.rb +312 -0
- data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +194 -0
- data/lib/rgeo/coord_sys/srs_database/interface.rb +165 -0
- data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +188 -0
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +108 -0
- data/lib/rgeo/coord_sys/srs_database/url_reader.rb +108 -0
- data/lib/rgeo/error.rb +63 -0
- data/lib/rgeo/feature.rb +88 -0
- data/lib/rgeo/feature/curve.rb +156 -0
- data/lib/rgeo/feature/factory.rb +332 -0
- data/lib/rgeo/feature/factory_generator.rb +138 -0
- data/lib/rgeo/feature/geometry.rb +614 -0
- data/lib/rgeo/feature/geometry_collection.rb +129 -0
- data/lib/rgeo/feature/line.rb +66 -0
- data/lib/rgeo/feature/line_string.rb +102 -0
- data/lib/rgeo/feature/linear_ring.rb +66 -0
- data/lib/rgeo/feature/multi_curve.rb +113 -0
- data/lib/rgeo/feature/multi_line_string.rb +66 -0
- data/lib/rgeo/feature/multi_point.rb +73 -0
- data/lib/rgeo/feature/multi_polygon.rb +97 -0
- data/lib/rgeo/feature/multi_surface.rb +116 -0
- data/lib/rgeo/feature/point.rb +120 -0
- data/lib/rgeo/feature/polygon.rb +141 -0
- data/lib/rgeo/feature/surface.rb +122 -0
- data/lib/rgeo/feature/types.rb +305 -0
- data/lib/rgeo/geographic.rb +75 -0
- data/lib/rgeo/geographic/factory.rb +287 -0
- data/lib/rgeo/geographic/interface.rb +410 -0
- data/lib/rgeo/geographic/proj4_projector.rb +98 -0
- data/lib/rgeo/geographic/projected_feature_classes.rb +213 -0
- data/lib/rgeo/geographic/projected_feature_methods.rb +228 -0
- data/lib/rgeo/geographic/projected_window.rb +467 -0
- data/lib/rgeo/geographic/simple_mercator_projector.rb +157 -0
- data/lib/rgeo/geographic/spherical_feature_classes.rb +212 -0
- data/lib/rgeo/geographic/spherical_feature_methods.rb +97 -0
- data/lib/rgeo/geographic/spherical_math.rb +206 -0
- data/lib/rgeo/geos.rb +72 -0
- data/lib/rgeo/geos/factory.rb +301 -0
- data/lib/rgeo/geos/impl_additions.rb +76 -0
- data/lib/rgeo/geos/interface.rb +139 -0
- data/lib/rgeo/geos/zm_factory.rb +275 -0
- data/lib/rgeo/geos/zm_impl.rb +432 -0
- data/lib/rgeo/impl_helper.rb +53 -0
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +235 -0
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +85 -0
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +197 -0
- data/lib/rgeo/impl_helper/basic_point_methods.rb +138 -0
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +121 -0
- data/lib/rgeo/impl_helper/math.rb +50 -0
- data/lib/rgeo/version.rb +52 -0
- data/lib/rgeo/wkrep.rb +72 -0
- data/lib/rgeo/wkrep/wkb_generator.rb +267 -0
- data/lib/rgeo/wkrep/wkb_parser.rb +315 -0
- data/lib/rgeo/wkrep/wkt_generator.rb +275 -0
- data/lib/rgeo/wkrep/wkt_parser.rb +496 -0
- data/test/common/geometry_collection_tests.rb +238 -0
- data/test/common/line_string_tests.rb +324 -0
- data/test/common/multi_line_string_tests.rb +209 -0
- data/test/common/multi_point_tests.rb +201 -0
- data/test/common/multi_polygon_tests.rb +208 -0
- data/test/common/point_tests.rb +331 -0
- data/test/common/polygon_tests.rb +232 -0
- data/test/coord_sys/tc_active_record_table.rb +102 -0
- data/test/coord_sys/tc_ogc_cs.rb +356 -0
- data/test/coord_sys/tc_proj4.rb +138 -0
- data/test/coord_sys/tc_proj4_srs_data.rb +76 -0
- data/test/coord_sys/tc_sr_org.rb +70 -0
- data/test/coord_sys/tc_url_reader.rb +82 -0
- data/test/geos/tc_factory.rb +91 -0
- data/test/geos/tc_geometry_collection.rb +62 -0
- data/test/geos/tc_line_string.rb +62 -0
- data/test/geos/tc_misc.rb +72 -0
- data/test/geos/tc_multi_line_string.rb +62 -0
- data/test/geos/tc_multi_point.rb +62 -0
- data/test/geos/tc_multi_polygon.rb +63 -0
- data/test/geos/tc_point.rb +86 -0
- data/test/geos/tc_polygon.rb +86 -0
- data/test/geos/tc_zmfactory.rb +85 -0
- data/test/projected_geographic/tc_geometry_collection.rb +62 -0
- data/test/projected_geographic/tc_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_point.rb +62 -0
- data/test/projected_geographic/tc_multi_polygon.rb +63 -0
- data/test/projected_geographic/tc_point.rb +93 -0
- data/test/projected_geographic/tc_polygon.rb +62 -0
- data/test/simple_cartesian/tc_calculations.rb +145 -0
- data/test/simple_cartesian/tc_geometry_collection.rb +69 -0
- data/test/simple_cartesian/tc_line_string.rb +70 -0
- data/test/simple_cartesian/tc_multi_line_string.rb +67 -0
- data/test/simple_cartesian/tc_multi_point.rb +67 -0
- data/test/simple_cartesian/tc_multi_polygon.rb +70 -0
- data/test/simple_cartesian/tc_point.rb +91 -0
- data/test/simple_cartesian/tc_polygon.rb +67 -0
- data/test/simple_mercator/tc_geometry_collection.rb +62 -0
- data/test/simple_mercator/tc_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_point.rb +62 -0
- data/test/simple_mercator/tc_multi_polygon.rb +63 -0
- data/test/simple_mercator/tc_point.rb +93 -0
- data/test/simple_mercator/tc_polygon.rb +62 -0
- data/test/simple_mercator/tc_window.rb +219 -0
- data/test/spherical_geographic/tc_calculations.rb +203 -0
- data/test/spherical_geographic/tc_geometry_collection.rb +70 -0
- data/test/spherical_geographic/tc_line_string.rb +70 -0
- data/test/spherical_geographic/tc_multi_line_string.rb +67 -0
- data/test/spherical_geographic/tc_multi_point.rb +67 -0
- data/test/spherical_geographic/tc_multi_polygon.rb +70 -0
- data/test/spherical_geographic/tc_point.rb +100 -0
- data/test/spherical_geographic/tc_polygon.rb +67 -0
- data/test/tc_cartesian_analysis.rb +107 -0
- data/test/tc_oneoff.rb +63 -0
- data/test/wkrep/tc_wkb_generator.rb +249 -0
- data/test/wkrep/tc_wkb_parser.rb +353 -0
- data/test/wkrep/tc_wkt_generator.rb +362 -0
- data/test/wkrep/tc_wkt_parser.rb +480 -0
- metadata +267 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Spherical geometry common methods
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module Cartesian
|
40
|
+
|
41
|
+
|
42
|
+
module GeometryMethods # :nodoc:
|
43
|
+
|
44
|
+
|
45
|
+
def srid
|
46
|
+
factory.srid
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def envelope
|
51
|
+
BoundingBox.new(factory).add(self).to_geometry
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
module LineStringMethods # :nodoc:
|
59
|
+
|
60
|
+
|
61
|
+
def _segments
|
62
|
+
unless @segments
|
63
|
+
@segments = (0..num_points-2).map do |i_|
|
64
|
+
Segment.new(point_n(i_), point_n(i_+1))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
@segments
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def is_simple?
|
72
|
+
segs_ = _segments
|
73
|
+
len_ = segs_.length
|
74
|
+
return false if segs_.any?{ |a_| a_.degenerate? }
|
75
|
+
return true if len_ == 1
|
76
|
+
return segs_[0].s != segs_[1].e if len_ == 2
|
77
|
+
segs_.each_with_index do |seg_, index_|
|
78
|
+
nindex_ = index_ + 1
|
79
|
+
nindex_ = nil if nindex_ == len_
|
80
|
+
return false if nindex_ && seg_.contains_point?(segs_[nindex_].e)
|
81
|
+
pindex_ = index_ - 1
|
82
|
+
pindex_ = nil if pindex_ < 0
|
83
|
+
return false if pindex_ && seg_.contains_point?(segs_[pindex_].s)
|
84
|
+
if nindex_
|
85
|
+
oindex_ = nindex_ + 1
|
86
|
+
while oindex_ < len_
|
87
|
+
oseg_ = segs_[oindex_]
|
88
|
+
return false if !(index_ == 0 && oindex_ == len_-1 && seg_.s == oseg_.e) && seg_.intersects_segment?(oseg_)
|
89
|
+
oindex_ += 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def length
|
98
|
+
@segments.inject(0.0){ |sum_, seg_| sum_ + seg_.length }
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Cartesian toplevel interface
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module Cartesian
|
40
|
+
|
41
|
+
class << self
|
42
|
+
|
43
|
+
|
44
|
+
# Creates and returns a cartesian factory of the preferred
|
45
|
+
# Cartesian implementation.
|
46
|
+
#
|
47
|
+
# The actual implementation returned depends on which ruby
|
48
|
+
# interpreter is running and what libraries are available.
|
49
|
+
# RGeo will try to provide a fully-functional and performant
|
50
|
+
# implementation if possible. If not, the simple Cartesian
|
51
|
+
# implementation will be returned.
|
52
|
+
# In practice, this means it returns a Geos implementation if
|
53
|
+
# available; otherwise it falls back to the simple implementation.
|
54
|
+
#
|
55
|
+
# The given options are passed to the factory's constructor.
|
56
|
+
# What options are available depends on the particular
|
57
|
+
# implementation. See Geos::factory and Cartesian::simple_factory
|
58
|
+
# for details. Unsupported options are ignored.
|
59
|
+
|
60
|
+
def preferred_factory(opts_={})
|
61
|
+
if ::RGeo::Geos.supported?
|
62
|
+
::RGeo::Geos.factory(opts_)
|
63
|
+
else
|
64
|
+
simple_factory(opts_)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
alias_method :factory, :preferred_factory
|
68
|
+
|
69
|
+
|
70
|
+
# Returns a factory for the simple Cartesian implementation. This
|
71
|
+
# implementation provides all SFS 1.1 types, and also allows Z and
|
72
|
+
# M coordinates. It does not depend on external libraries, and is
|
73
|
+
# thus always available, but it does not implement many of the more
|
74
|
+
# advanced geometric operations. These limitations are:
|
75
|
+
#
|
76
|
+
# * Relational operators such as Feature::Geometry#intersects? are
|
77
|
+
# not implemented for most types.
|
78
|
+
# * Relational constructors such as Feature::Geometry#union are
|
79
|
+
# not implemented for most types.
|
80
|
+
# * Buffer and convex hull calculations are not implemented for most
|
81
|
+
# types. Boundaries are available except for GeometryCollection.
|
82
|
+
# * Length calculations are available, but areas are not. Distances
|
83
|
+
# are available only between points.
|
84
|
+
# * Equality and simplicity evaluation are implemented for some but
|
85
|
+
# not all types.
|
86
|
+
# * Assertions for polygons and multipolygons are not implemented.
|
87
|
+
#
|
88
|
+
# Unimplemented operations may raise Error::UnsupportedOperation
|
89
|
+
# if invoked.
|
90
|
+
#
|
91
|
+
# Options include:
|
92
|
+
#
|
93
|
+
# [<tt>:srid</tt>]
|
94
|
+
# Set the SRID returned by geometries created by this factory.
|
95
|
+
# Default is 0.
|
96
|
+
# [<tt>:proj4</tt>]
|
97
|
+
# The coordinate system in Proj4 format, either as a
|
98
|
+
# CoordSys::Proj4 object or as a string or hash representing the
|
99
|
+
# proj4 format. Optional.
|
100
|
+
# [<tt>:coord_sys</tt>]
|
101
|
+
# The coordinate system in OGC form, either as a subclass of
|
102
|
+
# CoordSys::CS::CoordinateSystem, or as a string in WKT format.
|
103
|
+
# Optional.
|
104
|
+
# [<tt>:srs_database</tt>]
|
105
|
+
# Optional. If provided, the value should be an implementation of
|
106
|
+
# CoordSys::SRSDatabase::Interface. If both this and an SRID are
|
107
|
+
# provided, they are used to look up the proj4 and coord_sys
|
108
|
+
# objects from a spatial reference system database.
|
109
|
+
# [<tt>:has_z_coordinate</tt>]
|
110
|
+
# Support a Z coordinate. Default is false.
|
111
|
+
# [<tt>:has_m_coordinate</tt>]
|
112
|
+
# Support an M coordinate. Default is false.
|
113
|
+
|
114
|
+
def simple_factory(opts_={})
|
115
|
+
Cartesian::Factory.new(opts_)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# Returns a Feature::FactoryGenerator that creates preferred
|
120
|
+
# factories. The given options are used as the default options.
|
121
|
+
#
|
122
|
+
# A common case for this is to provide the <tt>:srs_database</tt>
|
123
|
+
# as a default. Then, the factory generator need only be passed
|
124
|
+
# an SRID and it will automatically fetch the appropriate Proj4
|
125
|
+
# and CoordSys objects.
|
126
|
+
|
127
|
+
def preferred_factory_generator(defaults_={})
|
128
|
+
::Proc.new{ |c_| preferred_factory(defaults_.merge(c_)) }
|
129
|
+
end
|
130
|
+
alias_method :factory_generator, :preferred_factory_generator
|
131
|
+
|
132
|
+
|
133
|
+
# Returns a Feature::FactoryGenerator that creates simple factories.
|
134
|
+
# The given options are used as the default options.
|
135
|
+
#
|
136
|
+
# A common case for this is to provide the <tt>:srs_database</tt>
|
137
|
+
# as a default. Then, the factory generator need only be passed
|
138
|
+
# an SRID and it will automatically fetch the appropriate Proj4
|
139
|
+
# and CoordSys objects.
|
140
|
+
|
141
|
+
def simple_factory_generator(defaults_={})
|
142
|
+
::Proc.new{ |c_| simple_factory(defaults_.merge(c_)) }
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Coordinate systems for RGeo
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
|
40
|
+
# This module provides data structures and tools related to coordinate
|
41
|
+
# systems and coordinate transforms. It comprises the following parts:
|
42
|
+
#
|
43
|
+
# RGeo::CoordSys::Proj4 is a wrapper around the proj4 library, which
|
44
|
+
# defines a commonly-used syntax for specifying geographic and projected
|
45
|
+
# coordinate systems, and performs coordinate transformations.
|
46
|
+
#
|
47
|
+
# The RGeo::CoordSys::CS module contains an implementation of the CS
|
48
|
+
# (coordinate systems) package of the OGC Coordinate Transform spec.
|
49
|
+
# This includes classes for representing ellipsoids, datums, coordinate
|
50
|
+
# systems, and other related concepts, as well as a parser for the WKT
|
51
|
+
# format for specifying coordinate systems.
|
52
|
+
#
|
53
|
+
# The RGeo::CoordSys::SRSDatabase module contains tools for accessing
|
54
|
+
# spatial reference databases, from which you can look up coordinate
|
55
|
+
# system specifications. You can access the <tt>spatial_ref_sys</tt>
|
56
|
+
# table provided with OGC-compliant spatial databases such as PostGIS,
|
57
|
+
# read the databases provided with the proj4 library, or access URLs
|
58
|
+
# such as those provided by spatialreference.org.
|
59
|
+
|
60
|
+
module CoordSys
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Implementation files
|
68
|
+
begin
|
69
|
+
require 'rgeo/coord_sys/proj4_c_impl'
|
70
|
+
rescue ::LoadError; end
|
71
|
+
require 'rgeo/coord_sys/proj4'
|
72
|
+
require 'rgeo/coord_sys/cs/factories'
|
73
|
+
require 'rgeo/coord_sys/cs/entities'
|
74
|
+
require 'rgeo/coord_sys/cs/wkt_parser'
|
75
|
+
require 'rgeo/coord_sys/srs_database/interface.rb'
|
76
|
+
require 'rgeo/coord_sys/srs_database/active_record_table.rb'
|
77
|
+
require 'rgeo/coord_sys/srs_database/proj4_data.rb'
|
78
|
+
require 'rgeo/coord_sys/srs_database/url_reader.rb'
|
79
|
+
require 'rgeo/coord_sys/srs_database/sr_org.rb'
|
@@ -0,0 +1,1524 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# -----------------------------------------------------------------------------
|
3
|
+
#
|
4
|
+
# OGC CS objects for RGeo
|
5
|
+
#
|
6
|
+
# -----------------------------------------------------------------------------
|
7
|
+
# Copyright 2010 Daniel Azuma
|
8
|
+
#
|
9
|
+
# All rights reserved.
|
10
|
+
#
|
11
|
+
# Redistribution and use in source and binary forms, with or without
|
12
|
+
# modification, are permitted provided that the following conditions are met:
|
13
|
+
#
|
14
|
+
# * Redistributions of source code must retain the above copyright notice,
|
15
|
+
# this list of conditions and the following disclaimer.
|
16
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
17
|
+
# this list of conditions and the following disclaimer in the documentation
|
18
|
+
# and/or other materials provided with the distribution.
|
19
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
20
|
+
# contributors to this software, may be used to endorse or promote products
|
21
|
+
# derived from this software without specific prior written permission.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
# -----------------------------------------------------------------------------
|
35
|
+
;
|
36
|
+
|
37
|
+
|
38
|
+
module RGeo
|
39
|
+
|
40
|
+
module CoordSys
|
41
|
+
|
42
|
+
|
43
|
+
module CS
|
44
|
+
|
45
|
+
|
46
|
+
# An axis orientation constant for AxisInfo.
|
47
|
+
# Unknown or unspecified axis orientation. This can be used for
|
48
|
+
# local or fitted coordinate systems.
|
49
|
+
AO_OTHER = 0
|
50
|
+
|
51
|
+
# An axis orientation constant for AxisInfo.
|
52
|
+
# Increasing ordinates values go North. This is usually used for
|
53
|
+
# Grid Y coordinates and Latitude.
|
54
|
+
AO_NORTH = 1
|
55
|
+
|
56
|
+
# An axis orientation constant for AxisInfo.
|
57
|
+
# Increasing ordinates values go South. This is rarely used.
|
58
|
+
AO_SOUTH = 2
|
59
|
+
|
60
|
+
# An axis orientation constant for AxisInfo.
|
61
|
+
# Increasing ordinates values go East. This is rarely used.
|
62
|
+
AO_EAST = 3
|
63
|
+
|
64
|
+
# An axis orientation constant for AxisInfo.
|
65
|
+
# Increasing ordinates values go West. This is usually used for
|
66
|
+
# Grid X coordinates and Longitude.
|
67
|
+
AO_WEST = 4
|
68
|
+
|
69
|
+
# An axis orientation constant for AxisInfo.
|
70
|
+
# Increasing ordinates values go up. This is used for vertical
|
71
|
+
# coordinate systems.
|
72
|
+
AO_UP = 5
|
73
|
+
|
74
|
+
# An axis orientation constant for AxisInfo.
|
75
|
+
# Increasing ordinates values go down. This is used for vertical
|
76
|
+
# coordinate systems.
|
77
|
+
AO_DOWN = 6
|
78
|
+
|
79
|
+
|
80
|
+
# A datum type constant for HorizontalDatum.
|
81
|
+
# Lowest possible value for horizontal datum types.
|
82
|
+
HD_MIN = 1000
|
83
|
+
|
84
|
+
# A datum type constant for HorizontalDatum.
|
85
|
+
# Unspecified horizontal datum type. Horizontal datums with this
|
86
|
+
# type should never supply a conversion to WGS84 using Bursa Wolf
|
87
|
+
# parameters.
|
88
|
+
HD_OTHER = 1000
|
89
|
+
|
90
|
+
# A datum type constant for HorizontalDatum.
|
91
|
+
# These datums, such as ED50, NAD27 and NAD83, have been designed
|
92
|
+
# to support horizontal positions on the ellipsoid as opposed to
|
93
|
+
# positions in 3-D space. These datums were designed mainly to
|
94
|
+
# support a horizontal component of a position in a domain of
|
95
|
+
# limited extent, such as a country, a region or a continent.
|
96
|
+
HD_CLASSIC = 1001
|
97
|
+
|
98
|
+
# A datum type constant for HorizontalDatum.
|
99
|
+
# A geocentric datum is a "satellite age" modern geodetic datum
|
100
|
+
# mainly of global extent, such as WGS84 (used in GPS), PZ90 (used
|
101
|
+
# in GLONASS) and ITRF. These datums were designed to support both
|
102
|
+
# a horizontal component of position and a vertical component of
|
103
|
+
# position (through ellipsoidal heights). The regional realizations
|
104
|
+
# of ITRF, such as ETRF, are also included in this category.
|
105
|
+
HD_GEOCENTRIC = 1002
|
106
|
+
|
107
|
+
# A datum type constant for HorizontalDatum.
|
108
|
+
# Highest possible value for horizontal datum types.
|
109
|
+
HD_MAX = 1999
|
110
|
+
|
111
|
+
# A datum type constant for VerticalDatum.
|
112
|
+
# Lowest possible value for vertical datum types.
|
113
|
+
VD_MIN = 2000
|
114
|
+
|
115
|
+
# A datum type constant for VerticalDatum.
|
116
|
+
# Unspecified vertical datum type.
|
117
|
+
VD_OTHER = 2000
|
118
|
+
|
119
|
+
# A datum type constant for VerticalDatum.
|
120
|
+
# A vertical datum for orthometric heights that are measured along
|
121
|
+
# the plumb line.
|
122
|
+
VD_ORTHOMETRIC = 2001
|
123
|
+
|
124
|
+
# A datum type constant for VerticalDatum.
|
125
|
+
# A vertical datum for ellipsoidal heights that are measured along
|
126
|
+
# the normal to the ellipsoid used in the definition of horizontal
|
127
|
+
# datum.
|
128
|
+
VD_ELLIPSOIDAL = 2002
|
129
|
+
|
130
|
+
# A datum type constant for VerticalDatum.
|
131
|
+
# The vertical datum of altitudes or heights in the atmosphere.
|
132
|
+
# These are approximations of orthometric heights obtained with the
|
133
|
+
# help of a barometer or a barometric altimeter. These values are
|
134
|
+
# usually expressed in one of the following units: meters, feet,
|
135
|
+
# millibars (used to measure pressure levels), or theta value (units
|
136
|
+
# used to measure geopotential height).
|
137
|
+
VD_ALTITUDE_BAROMETRIC = 2003
|
138
|
+
|
139
|
+
# A datum type constant for VerticalDatum.
|
140
|
+
# A normal height system.
|
141
|
+
VD_NORMAL = 2004
|
142
|
+
|
143
|
+
# A datum type constant for VerticalDatum.
|
144
|
+
# A vertical datum of geoid model derived heights, also called
|
145
|
+
# GPS-derived heights. These heights are approximations of
|
146
|
+
# orthometric heights (H), constructed from the ellipsoidal heights
|
147
|
+
# (h) by the use of the given geoid undulation model (N) through
|
148
|
+
# the equation: H=h-N.
|
149
|
+
VD_GEOID_MODE_DERIVED = 2005
|
150
|
+
|
151
|
+
# A datum type constant for VerticalDatum.
|
152
|
+
# This attribute is used to support the set of datums generated for
|
153
|
+
# hydrographic engineering projects where depth measurements below
|
154
|
+
# sea level are needed. It is often called a hydrographic or a
|
155
|
+
# marine datum. Depths are measured in the direction perpendicular
|
156
|
+
# (approximately) to the actual equipotential surfaces of the
|
157
|
+
# earth's gravity field, using such procedures as echo-sounding.
|
158
|
+
VD_DEPTH = 2006
|
159
|
+
|
160
|
+
# A datum type constant for VerticalDatum.
|
161
|
+
# Highest possible value for vertical datum types.
|
162
|
+
VD_MAX = 2999
|
163
|
+
|
164
|
+
# A datum type constant for LocalDatum.
|
165
|
+
# Lowest possible value for local datum types.
|
166
|
+
LD_MIN = 10000
|
167
|
+
|
168
|
+
# A datum type constant for LocalDatum.
|
169
|
+
# Highest possible value for local datum types.
|
170
|
+
LD_MAX = 32767
|
171
|
+
|
172
|
+
|
173
|
+
# This is a base class for all OGC coordinate system objects.
|
174
|
+
# This includes both interfaces and data types from the OGC
|
175
|
+
# Coordinate Transformation spec.
|
176
|
+
#
|
177
|
+
# This is a non-instantiable abstract class.
|
178
|
+
|
179
|
+
class Base
|
180
|
+
|
181
|
+
|
182
|
+
def inspect # :nodoc:
|
183
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} #{to_wkt}>"
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Tests for equality. Two objects are defined as equal if they
|
188
|
+
# have the same type (class) and the same WKT representation.
|
189
|
+
|
190
|
+
def eql?(rhs_)
|
191
|
+
rhs_.class == self.class && rhs_.to_wkt == self.to_wkt
|
192
|
+
end
|
193
|
+
alias_method :==, :eql?
|
194
|
+
|
195
|
+
|
196
|
+
# Returns the default WKT representation.
|
197
|
+
|
198
|
+
def to_s
|
199
|
+
to_wkt
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
# Computes the WKT representation. Options include:
|
204
|
+
#
|
205
|
+
# [<tt>:standard_brackets</tt>]
|
206
|
+
# If set to true, outputs parentheses rather than square
|
207
|
+
# brackets. Default is false.
|
208
|
+
|
209
|
+
def to_wkt(opts_={})
|
210
|
+
opts_[:standard_brackets] ? _to_wkt('(', ')') : _to_wkt('[', ']')
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
def _to_wkt(open_, close_) # :nodoc:
|
215
|
+
content_ = _wkt_content(open_, close_).map{ |obj_| ",#{obj_}" }.join
|
216
|
+
if defined?(@authority) && @authority
|
217
|
+
authority_ = ",AUTHORITY#{open_}#{@authority.inspect},#{@authority_code.inspect}#{close_}"
|
218
|
+
else
|
219
|
+
authority_ = ''
|
220
|
+
end
|
221
|
+
"#{_wkt_typename}#{open_}#{@name.inspect}#{content_}#{authority_}#{close_}"
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
class << self
|
226
|
+
|
227
|
+
private :new
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
# == OGC spec description
|
236
|
+
#
|
237
|
+
# Details of axis. This is used to label axes, and indicate the
|
238
|
+
# orientation.
|
239
|
+
|
240
|
+
class AxisInfo < Base
|
241
|
+
|
242
|
+
# :stopdoc:
|
243
|
+
NAMES_BY_VALUE = ['OTHER', 'NORTH', 'SOUTH', 'EAST', 'WEST', 'UP', 'DOWN']
|
244
|
+
# :startdoc:
|
245
|
+
|
246
|
+
def initialize(name_, orientation_) # :nodoc:
|
247
|
+
@name = name_
|
248
|
+
case orientation_
|
249
|
+
when ::String, ::Symbol
|
250
|
+
@orientation = NAMES_BY_VALUE.index(orientation_.to_s.upcase).to_i
|
251
|
+
else
|
252
|
+
@orientation = orientation_.to_i
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
# Human readable name for axis. Possible values are "X", "Y",
|
258
|
+
# "Long", "Lat" or any other short string.
|
259
|
+
attr_reader :name
|
260
|
+
|
261
|
+
# Gets enumerated value for orientation.
|
262
|
+
attr_reader :orientation
|
263
|
+
|
264
|
+
|
265
|
+
def _wkt_typename # :nodoc:
|
266
|
+
"AXIS"
|
267
|
+
end
|
268
|
+
|
269
|
+
def _wkt_content(open_, close_) # :nodoc:
|
270
|
+
[NAMES_BY_VALUE[@orientation]]
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
class << self
|
275
|
+
|
276
|
+
|
277
|
+
# Creates an AxisInfo. you must pass the human readable name for
|
278
|
+
# the axis (e.g. "X", "Y", "Long", "Lat", or other short string)
|
279
|
+
# and either an integer orientation code or a string. Possible
|
280
|
+
# orientation values are "<tt>OTHER</tt>", "<tt>NORTH</tt>",
|
281
|
+
# "<tt>SOUTH</tt>", "<tt>EAST</tt>", "<tt>WEST</tt>",
|
282
|
+
# "<tt>UP</tt>", and "<tt>DOWN</tt>", or the corresponding
|
283
|
+
# integer values 0-5.
|
284
|
+
|
285
|
+
def create(name_, orientation_)
|
286
|
+
new(name_, orientation_)
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
# == OGC spec description
|
296
|
+
#
|
297
|
+
# A named projection parameter value. The linear units of
|
298
|
+
# parameters' values match the linear units of the containing
|
299
|
+
# projected coordinate system. The angular units of parameter
|
300
|
+
# values match the angular units of the geographic coordinate
|
301
|
+
# system that the projected coordinate system is based on.
|
302
|
+
|
303
|
+
class ProjectionParameter < Base
|
304
|
+
|
305
|
+
def initialize(name_, value_) # :nodoc:
|
306
|
+
@name = name_
|
307
|
+
@value = value_.to_f
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
# The parameter name.
|
312
|
+
attr_reader :name
|
313
|
+
|
314
|
+
# The parameter value.
|
315
|
+
attr_reader :value
|
316
|
+
|
317
|
+
|
318
|
+
def _wkt_typename # :nodoc:
|
319
|
+
"PARAMETER"
|
320
|
+
end
|
321
|
+
|
322
|
+
def _wkt_content(open_, close_) # :nodoc:
|
323
|
+
[@value]
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
class << self
|
328
|
+
|
329
|
+
|
330
|
+
# Create a parameter given the name and value.
|
331
|
+
|
332
|
+
def create(name_, value_)
|
333
|
+
new(name_, value_)
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
end
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
# == OGC spec description
|
343
|
+
#
|
344
|
+
# Parameters for a geographic transformation into WGS84. The Bursa
|
345
|
+
# Wolf parameters should be applied to geocentric coordinates, where
|
346
|
+
# the X axis points towards the Greenwich Prime Meridian, the Y axis
|
347
|
+
# points East, and the Z axis points North.
|
348
|
+
|
349
|
+
class WGS84ConversionInfo < Base
|
350
|
+
|
351
|
+
def initialize(dx_, dy_, dz_, ex_, ey_, ez_, ppm_) # :nodoc:
|
352
|
+
@dx = dx_.to_f
|
353
|
+
@dy = dy_.to_f
|
354
|
+
@dz = dz_.to_f
|
355
|
+
@ex = ex_.to_f
|
356
|
+
@ey = ey_.to_f
|
357
|
+
@ez = ez_.to_f
|
358
|
+
@ppm = ppm_.to_f
|
359
|
+
end
|
360
|
+
|
361
|
+
|
362
|
+
# Bursa Wolf shift in meters.
|
363
|
+
attr_reader :dx
|
364
|
+
|
365
|
+
# Bursa Wolf shift in meters.
|
366
|
+
attr_reader :dy
|
367
|
+
|
368
|
+
# Bursa Wolf shift in meters.
|
369
|
+
attr_reader :dz
|
370
|
+
|
371
|
+
# Bursa Wolf rotation in arc seconds.
|
372
|
+
attr_reader :ex
|
373
|
+
|
374
|
+
# Bursa Wolf rotation in arc seconds.
|
375
|
+
attr_reader :ey
|
376
|
+
|
377
|
+
# Bursa Wolf rotation in arc seconds.
|
378
|
+
attr_reader :ez
|
379
|
+
|
380
|
+
# Bursa Wolf scaling in in parts per million.
|
381
|
+
attr_reader :ppm
|
382
|
+
|
383
|
+
|
384
|
+
def _to_wkt(open_, close_) # :nodoc:
|
385
|
+
"TOWGS84#{open_}#{@dx},#{@dy},#{@dz},#{@ex},#{@ey},#{@ez},#{@ppm}#{close_}"
|
386
|
+
end
|
387
|
+
|
388
|
+
|
389
|
+
class << self
|
390
|
+
|
391
|
+
|
392
|
+
# Create the horizontal datum shift transformation into WGS84,
|
393
|
+
# given the seven Bursa Wolf parameters.
|
394
|
+
# The Bursa Wolf shift should be in meters, the rotation in arc
|
395
|
+
# seconds, and the scaling in parts per million.
|
396
|
+
|
397
|
+
def create(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
|
398
|
+
new(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
|
399
|
+
end
|
400
|
+
|
401
|
+
|
402
|
+
end
|
403
|
+
|
404
|
+
end
|
405
|
+
|
406
|
+
|
407
|
+
# == OGC spec description
|
408
|
+
#
|
409
|
+
# A base interface for metadata applicable to coordinate system
|
410
|
+
# objects.
|
411
|
+
#
|
412
|
+
# The metadata items "Abbreviation"’, "Alias", "Authority",
|
413
|
+
# "AuthorityCode", "Name" and "Remarks" were specified in the Simple
|
414
|
+
# Features interfaces, so they have been kept here.
|
415
|
+
#
|
416
|
+
# This specification does not dictate what the contents of these
|
417
|
+
# items should be. However, the following guidelines are suggested:
|
418
|
+
#
|
419
|
+
# When CS_CoordinateSystemAuthorityFactory is used to create an
|
420
|
+
# object, the "Authority" and "AuthorityCode" values should be set
|
421
|
+
# to the authority name of the factory object, and the authority
|
422
|
+
# code supplied by the client, respectively. The other values may or
|
423
|
+
# may not be set. (If the authority is EPSG, the implementer may
|
424
|
+
# consider using the corresponding metadata values in the EPSG
|
425
|
+
# tables.)
|
426
|
+
#
|
427
|
+
# When CS_CoordinateSystemFactory creates an object, the "Name"
|
428
|
+
# should be set to the value supplied by the client. All of the
|
429
|
+
# other metadata items should be left empty.
|
430
|
+
#
|
431
|
+
# == Notes
|
432
|
+
#
|
433
|
+
# This is a non-instantiable abstract class.
|
434
|
+
#
|
435
|
+
# Most subclasses will have a set of optional parameters in their
|
436
|
+
# "create" method to set the metadata fields. These parameters are,
|
437
|
+
# in order:
|
438
|
+
#
|
439
|
+
# * <b>authority</b>: authority name
|
440
|
+
# * <b>authority_code</b>: authority-specific identification code
|
441
|
+
# * <b>abbreviation</b>: an abbreviation
|
442
|
+
# * <b>alias</b>: an alias
|
443
|
+
# * <b>remarks</b>: provider-supplied remarks.
|
444
|
+
|
445
|
+
class Info < Base
|
446
|
+
|
447
|
+
def initialize(name_, authority_=nil, authority_code_=nil, abbreviation_=nil, alias_=nil, remarks_=nil) # :nodoc:
|
448
|
+
@name = name_
|
449
|
+
@authority = authority_ ? authority_.to_s : nil
|
450
|
+
@authority_code = authority_code_ ? authority_code_.to_s : nil
|
451
|
+
@abbreviation = abbreviation_ ? abbreviation_.to_s : nil
|
452
|
+
@alias = alias_ ? alias_.to_s : nil
|
453
|
+
@remarks = remarks_ ? remarks_.to_s : nil
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
# Gets the abbreviation.
|
458
|
+
attr_reader :abbreviation
|
459
|
+
|
460
|
+
# Gets the alias.
|
461
|
+
attr_reader :alias
|
462
|
+
|
463
|
+
# Gets the authority name.
|
464
|
+
# An Authority is an organization that maintains definitions of
|
465
|
+
# Authority Codes. For example the European Petroleum Survey Group
|
466
|
+
# (EPSG) maintains a database of coordinate systems, and other
|
467
|
+
# spatial referencing objects, where each object has a code number
|
468
|
+
# ID. For example, the EPSG code for a WGS84 Lat/Lon coordinate
|
469
|
+
# system is "4326".
|
470
|
+
attr_reader :authority
|
471
|
+
|
472
|
+
# Gets the authority-specific identification code.
|
473
|
+
# The AuthorityCode is a compact string defined by an Authority to
|
474
|
+
# reference a particular spatial reference object. For example,
|
475
|
+
# the European Survey Group (EPSG) authority uses 32 bit integers
|
476
|
+
# to reference coordinate systems, so all their code strings will
|
477
|
+
# consist of a few digits. The EPSG code for WGS84 Lat/Lon is
|
478
|
+
# "4326".
|
479
|
+
attr_reader :authority_code
|
480
|
+
|
481
|
+
# Gets the name.
|
482
|
+
attr_reader :name
|
483
|
+
|
484
|
+
# Gets the provider-supplied remarks.
|
485
|
+
attr_reader :remarks
|
486
|
+
|
487
|
+
|
488
|
+
end
|
489
|
+
|
490
|
+
|
491
|
+
# == OGC spec description
|
492
|
+
#
|
493
|
+
# Base interface for defining units.
|
494
|
+
#
|
495
|
+
# == Notes
|
496
|
+
#
|
497
|
+
# Normally, you will instantiate one of the subclasses LinearUnit or
|
498
|
+
# AngularUnit. However, it is possible to instantiate Unit if it is
|
499
|
+
# not clear whether the data refers to a LinearUnit or AngularUnit.
|
500
|
+
|
501
|
+
class Unit < Info
|
502
|
+
|
503
|
+
def initialize(name_, conversion_factor_, *optional_) # :nodoc:
|
504
|
+
super(name_, *optional_)
|
505
|
+
@conversion_factor = conversion_factor_.to_f
|
506
|
+
end
|
507
|
+
|
508
|
+
|
509
|
+
# This field is not part of the OGC CT spec, but is part of the
|
510
|
+
# SFS. It is an alias of the appropriate field in the subclass,
|
511
|
+
# i.e. LinearUnit#meters_per_unit or AngularUnit#radians_per_unit.
|
512
|
+
attr_reader :conversion_factor
|
513
|
+
|
514
|
+
|
515
|
+
def _wkt_typename # :nodoc:
|
516
|
+
"UNIT"
|
517
|
+
end
|
518
|
+
|
519
|
+
def _wkt_content(open_, close_) # :nodoc:
|
520
|
+
[@conversion_factor]
|
521
|
+
end
|
522
|
+
|
523
|
+
|
524
|
+
class << self
|
525
|
+
|
526
|
+
|
527
|
+
# Create a bare Unit that does not specify whether it is a
|
528
|
+
# LinearUnit or an AngularUnit, given a unit name and a
|
529
|
+
# conversion factor. You may also provide the optional
|
530
|
+
# parameters specified by the Info interface.
|
531
|
+
|
532
|
+
def create(name_, conversion_factor_, *optional_)
|
533
|
+
new(name_, conversion_factor_, *optional_)
|
534
|
+
end
|
535
|
+
|
536
|
+
|
537
|
+
end
|
538
|
+
|
539
|
+
end
|
540
|
+
|
541
|
+
|
542
|
+
# == OGC spec description
|
543
|
+
#
|
544
|
+
# Definition of linear units.
|
545
|
+
|
546
|
+
class LinearUnit < Unit
|
547
|
+
|
548
|
+
|
549
|
+
# Returns the number of meters per LinearUnit.
|
550
|
+
# Also available as Unit#conversion_factor.
|
551
|
+
|
552
|
+
def meters_per_unit
|
553
|
+
@conversion_factor
|
554
|
+
end
|
555
|
+
|
556
|
+
|
557
|
+
class << self
|
558
|
+
|
559
|
+
|
560
|
+
# Create a LinearUnit given a unit name and a conversion factor
|
561
|
+
# in meters per unit. You may also provide the optional
|
562
|
+
# parameters specified by the Info interface.
|
563
|
+
|
564
|
+
def create(name_, meters_per_unit_, *optional_)
|
565
|
+
new(name_, meters_per_unit_, *optional_)
|
566
|
+
end
|
567
|
+
|
568
|
+
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
|
574
|
+
# == OGC spec description
|
575
|
+
#
|
576
|
+
# Definition of angular units.
|
577
|
+
|
578
|
+
class AngularUnit < Unit
|
579
|
+
|
580
|
+
|
581
|
+
# Returns the number of radians per AngularUnit.
|
582
|
+
# Also available as Unit#conversion_factor.
|
583
|
+
|
584
|
+
def radians_per_unit
|
585
|
+
@conversion_factor
|
586
|
+
end
|
587
|
+
|
588
|
+
|
589
|
+
class << self
|
590
|
+
|
591
|
+
|
592
|
+
# Create an AngularUnit given a unit name and a conversion
|
593
|
+
# factor in radians per unit. You may also provide the optional
|
594
|
+
# parameters specified by the Info interface.
|
595
|
+
|
596
|
+
def create(name_, radians_per_unit_, *optional_)
|
597
|
+
new(name_, radians_per_unit_, *optional_)
|
598
|
+
end
|
599
|
+
|
600
|
+
|
601
|
+
end
|
602
|
+
|
603
|
+
end
|
604
|
+
|
605
|
+
|
606
|
+
# == OGC spec description
|
607
|
+
#
|
608
|
+
# A meridian used to take longitude measurements from.
|
609
|
+
|
610
|
+
class PrimeMeridian < Info
|
611
|
+
|
612
|
+
def initialize(name_, angular_unit_, longitude_, *optional_) # :nodoc:
|
613
|
+
super(name_, *optional_)
|
614
|
+
@angular_unit = angular_unit_
|
615
|
+
@longitude = longitude_.to_f
|
616
|
+
end
|
617
|
+
|
618
|
+
|
619
|
+
# Returns the AngularUnits.
|
620
|
+
attr_reader :angular_unit
|
621
|
+
|
622
|
+
# Returns the longitude value relative to the Greenwich Meridian.
|
623
|
+
# The longitude is expressed in this objects angular units.
|
624
|
+
attr_reader :longitude
|
625
|
+
|
626
|
+
|
627
|
+
def _wkt_typename # :nodoc:
|
628
|
+
"PRIMEM"
|
629
|
+
end
|
630
|
+
|
631
|
+
def _wkt_content(open_, close_) # :nodoc:
|
632
|
+
[@longitude]
|
633
|
+
end
|
634
|
+
|
635
|
+
|
636
|
+
class << self
|
637
|
+
|
638
|
+
|
639
|
+
# Create a PrimeMeridian given a name, AngularUnits, and the
|
640
|
+
# longitude relative to the Greenwich Meridian, expressed in
|
641
|
+
# the AngularUnits. You may also provide the optional parameters
|
642
|
+
# specified by the Info interface.
|
643
|
+
|
644
|
+
def create(name_, angular_unit_, longitude_, *optional_)
|
645
|
+
new(name_, angular_unit_, longitude_, *optional_)
|
646
|
+
end
|
647
|
+
|
648
|
+
|
649
|
+
end
|
650
|
+
|
651
|
+
|
652
|
+
end
|
653
|
+
|
654
|
+
|
655
|
+
# == OGC spec description
|
656
|
+
#
|
657
|
+
# An approximation of the Earth's surface as a squashed sphere.
|
658
|
+
|
659
|
+
class Ellipsoid < Info
|
660
|
+
|
661
|
+
def initialize(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_) # :nodoc:
|
662
|
+
super(name_, *optional_)
|
663
|
+
@semi_major_axis = semi_major_axis_.to_f
|
664
|
+
@semi_minor_axis = semi_minor_axis_.to_f
|
665
|
+
@inverse_flattening = inverse_flattening_.to_f
|
666
|
+
@ivf_definitive = ivf_definitive_ ? true : false
|
667
|
+
@linear_unit = linear_unit_
|
668
|
+
end
|
669
|
+
|
670
|
+
|
671
|
+
# Gets the equatorial radius. The returned length is expressed in
|
672
|
+
# this object's axis units.
|
673
|
+
attr_reader :semi_major_axis
|
674
|
+
|
675
|
+
# Gets the polar radius. The returned length is expressed in this
|
676
|
+
# object's axis units.
|
677
|
+
attr_reader :semi_minor_axis
|
678
|
+
|
679
|
+
# Returns the value of the inverse of the flattening constant. The
|
680
|
+
# inverse flattening is related to the equatorial/polar radius by
|
681
|
+
# the formula ivf=re/(re-rp). For perfect spheres, this formula
|
682
|
+
# breaks down, and a special IVF value of zero is used.
|
683
|
+
attr_reader :inverse_flattening
|
684
|
+
|
685
|
+
# Is the Inverse Flattening definitive for this ellipsoid? Some
|
686
|
+
# ellipsoids use the IVF as the defining value, and calculate the
|
687
|
+
# polar radius whenever asked. Other ellipsoids use the polar
|
688
|
+
# radius to calculate the IVF whenever asked. This distinction can
|
689
|
+
# be important to avoid floating-point rounding errors.
|
690
|
+
attr_reader :ivf_definitive
|
691
|
+
|
692
|
+
# Returns the LinearUnit. The units of the semi-major and
|
693
|
+
# semi-minor axis values.
|
694
|
+
attr_reader :axis_unit
|
695
|
+
|
696
|
+
|
697
|
+
def _wkt_typename # :nodoc:
|
698
|
+
"SPHEROID"
|
699
|
+
end
|
700
|
+
|
701
|
+
def _wkt_content(open_, close_) # :nodoc:
|
702
|
+
[@semi_major_axis, @inverse_flattening]
|
703
|
+
end
|
704
|
+
|
705
|
+
|
706
|
+
class << self
|
707
|
+
|
708
|
+
|
709
|
+
# Create an Ellipsoid given a name, semi-major and semi-minor
|
710
|
+
# axes, the inverse flattening, a boolean indicating whether
|
711
|
+
# the inverse flattening is definitive, and the LinearUnit
|
712
|
+
# indicating the axis units. The LinearUnit is optional and
|
713
|
+
# may be set to nil. You may also provide the optional parameters
|
714
|
+
# specified by the Info interface.
|
715
|
+
|
716
|
+
def create(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
|
717
|
+
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
|
718
|
+
end
|
719
|
+
|
720
|
+
|
721
|
+
# Create an Ellipsoid given a name, semi-major and semi-minor
|
722
|
+
# axes, and the LinearUnit indicating the axis units. In the
|
723
|
+
# resulting ellipsoid, the inverse flattening is not definitive.
|
724
|
+
# The LinearUnit is optional and may be set to nil. You may also
|
725
|
+
# provide the optional parameters specified by the Info interface.
|
726
|
+
|
727
|
+
def create_ellipsoid(name_, semi_major_axis_, semi_minor_axis_, linear_unit_, *optional_)
|
728
|
+
semi_major_axis_ = semi_major_axis_.to_f
|
729
|
+
semi_minor_axis_ = semi_minor_axis_.to_f
|
730
|
+
inverse_flattening_ = semi_major_axis_ / (semi_major_axis_ - semi_minor_axis_)
|
731
|
+
inverse_flattening_ = 0.0 if inverse_flattening_.infinite?
|
732
|
+
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, false, linear_unit_, *optional_)
|
733
|
+
end
|
734
|
+
|
735
|
+
|
736
|
+
# Create an Ellipsoid given a name, semi-major axis, inverse
|
737
|
+
# flattening, and the LinearUnit indicating the axis units. In
|
738
|
+
# the resulting ellipsoid, the inverse flattening is definitive.
|
739
|
+
# The LinearUnit is optional and may be set to nil. You may also
|
740
|
+
# provide the optional parameters specified by the Info interface.
|
741
|
+
|
742
|
+
def create_flattened_sphere(name_, semi_major_axis_, inverse_flattening_, linear_unit_, *optional_)
|
743
|
+
semi_major_axis_ = semi_major_axis_.to_f
|
744
|
+
inverse_flattening_ = inverse_flattening_.to_f
|
745
|
+
semi_minor_axis_ = semi_major_axis_ - semi_major_axis_ / inverse_flattening_
|
746
|
+
semi_minor_axis_ = semi_major_axis_ if semi_minor_axis_.infinite?
|
747
|
+
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, true, linear_unit_, *optional_)
|
748
|
+
end
|
749
|
+
|
750
|
+
|
751
|
+
end
|
752
|
+
|
753
|
+
end
|
754
|
+
|
755
|
+
|
756
|
+
# == OGC spec description
|
757
|
+
#
|
758
|
+
# A set of quantities from which other quantities are calculated.
|
759
|
+
# For the OGC abstract model, it can be defined as a set of real
|
760
|
+
# points on the earth that have coordinates. EG. A datum can be
|
761
|
+
# thought of as a set of parameters defining completely the origin
|
762
|
+
# and orientation of a coordinate system with respect to the earth.
|
763
|
+
# A textual description and/or a set of parameters describing the
|
764
|
+
# relationship of a coordinate system to some predefined physical
|
765
|
+
# locations (such as center of mass) and physical directions (such
|
766
|
+
# as axis of spin). The definition of the datum may also include
|
767
|
+
# the temporal behavior (such as the rate of change of the
|
768
|
+
# orientation of the coordinate axes).
|
769
|
+
#
|
770
|
+
# == Notes
|
771
|
+
#
|
772
|
+
# This is a non-instantiable abstract class. You must instantiate
|
773
|
+
# one of the subclasses HorizontalDatum, VerticalDatum, or
|
774
|
+
# LocalDatum.
|
775
|
+
|
776
|
+
class Datum < Info
|
777
|
+
|
778
|
+
def initialize(name_, datum_type_, *optional_) # :nodoc:
|
779
|
+
super(name_, *optional_)
|
780
|
+
@datum_type = datum_type_.to_i
|
781
|
+
end
|
782
|
+
|
783
|
+
|
784
|
+
# Gets the type of the datum as an enumerated code.
|
785
|
+
attr_reader :datum_type
|
786
|
+
|
787
|
+
|
788
|
+
def _wkt_content(open_, close_) # :nodoc:
|
789
|
+
[]
|
790
|
+
end
|
791
|
+
|
792
|
+
|
793
|
+
end
|
794
|
+
|
795
|
+
|
796
|
+
# == OGC spec description
|
797
|
+
#
|
798
|
+
# Procedure used to measure vertical distances.
|
799
|
+
|
800
|
+
class VerticalDatum < Datum
|
801
|
+
|
802
|
+
def _wkt_typename # :nodoc:
|
803
|
+
"VERT_DATUM"
|
804
|
+
end
|
805
|
+
|
806
|
+
def _wkt_content(open_, close_) # :nodoc:
|
807
|
+
[@datum_type]
|
808
|
+
end
|
809
|
+
|
810
|
+
class << self
|
811
|
+
|
812
|
+
|
813
|
+
# Create a VerticalDatum given a name and a datum type code.
|
814
|
+
# You may also provide the optional parameters specified by the
|
815
|
+
# Info interface.
|
816
|
+
|
817
|
+
def create(name_, datum_type_, *optional_)
|
818
|
+
new(name_, datum_type_, *optional_)
|
819
|
+
end
|
820
|
+
|
821
|
+
|
822
|
+
end
|
823
|
+
|
824
|
+
end
|
825
|
+
|
826
|
+
|
827
|
+
# == OGC spec description
|
828
|
+
#
|
829
|
+
# Local datum. If two local datum objects have the same datum type
|
830
|
+
# and name, then they can be considered equal. This means that
|
831
|
+
# coordinates can be transformed between two different local
|
832
|
+
# coordinate systems, as long as they are based on the same local
|
833
|
+
# datum.
|
834
|
+
|
835
|
+
class LocalDatum < Datum
|
836
|
+
|
837
|
+
def _wkt_typename # :nodoc:
|
838
|
+
"LOCAL_DATUM"
|
839
|
+
end
|
840
|
+
|
841
|
+
def _wkt_content(open_, close_) # :nodoc:
|
842
|
+
[@datum_type]
|
843
|
+
end
|
844
|
+
|
845
|
+
class << self
|
846
|
+
|
847
|
+
|
848
|
+
# Create a LocalDatum given a name and a datum type code. You
|
849
|
+
# may also provide the optional parameters specified by the
|
850
|
+
# Info interface.
|
851
|
+
|
852
|
+
def create(name_, datum_type_, *optional_)
|
853
|
+
new(name_, datum_type_, *optional_)
|
854
|
+
end
|
855
|
+
|
856
|
+
|
857
|
+
end
|
858
|
+
|
859
|
+
end
|
860
|
+
|
861
|
+
|
862
|
+
# == OGC spec description
|
863
|
+
#
|
864
|
+
# Procedure used to measure positions on the surface of the Earth.
|
865
|
+
|
866
|
+
class HorizontalDatum < Datum
|
867
|
+
|
868
|
+
def initialize(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_) # :nodoc:
|
869
|
+
super(name_, datum_type_, *optional_)
|
870
|
+
@ellipsoid = ellipsoid_
|
871
|
+
@wgs84_parameters = wgs84_parameters_
|
872
|
+
end
|
873
|
+
|
874
|
+
|
875
|
+
# Returns the Ellipsoid.
|
876
|
+
attr_reader :ellipsoid
|
877
|
+
|
878
|
+
# Gets preferred parameters for a Bursa Wolf transformation into
|
879
|
+
# WGS84. The 7 returned values correspond to (dx,dy,dz) in meters,
|
880
|
+
# (ex,ey,ez) in arc-seconds, and scaling in parts-per-million.
|
881
|
+
attr_reader :wgs84_parameters
|
882
|
+
|
883
|
+
|
884
|
+
def _wkt_typename # :nodoc:
|
885
|
+
"DATUM"
|
886
|
+
end
|
887
|
+
|
888
|
+
def _wkt_content(open_, close_) # :nodoc:
|
889
|
+
array_ = [@ellipsoid._to_wkt(open_, close_)]
|
890
|
+
array_ << @wgs84_parameters._to_wkt(open_, close_) if @wgs84_parameters
|
891
|
+
array_
|
892
|
+
end
|
893
|
+
|
894
|
+
|
895
|
+
class << self
|
896
|
+
|
897
|
+
|
898
|
+
# Create a HorizontalDatum given a name, datum type code,
|
899
|
+
# Ellipsoid, and WGS84ConversionInfo. The WGS84ConversionInfo
|
900
|
+
# is optional and may be set to nil. You may also provide the
|
901
|
+
# optional parameters specified by the Info interface.
|
902
|
+
|
903
|
+
def create(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
|
904
|
+
new(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
|
905
|
+
end
|
906
|
+
|
907
|
+
|
908
|
+
end
|
909
|
+
|
910
|
+
end
|
911
|
+
|
912
|
+
|
913
|
+
# == OGC spec description
|
914
|
+
#
|
915
|
+
# A projection from geographic coordinates to projected coordinates.
|
916
|
+
|
917
|
+
class Projection < Info
|
918
|
+
|
919
|
+
def initialize(name_, class_name_, parameters_, *optional_) # :nodoc:
|
920
|
+
super(name_, *optional_)
|
921
|
+
@class_name = class_name_.to_s
|
922
|
+
@parameters = parameters_ ? parameters_.dup : []
|
923
|
+
end
|
924
|
+
|
925
|
+
|
926
|
+
# Gets the projection classification name
|
927
|
+
# (e.g. "Transverse_Mercator").
|
928
|
+
attr_reader :class_name
|
929
|
+
|
930
|
+
|
931
|
+
# Gets number of parameters of the projection.
|
932
|
+
|
933
|
+
def num_parameters
|
934
|
+
@parameters.size
|
935
|
+
end
|
936
|
+
|
937
|
+
|
938
|
+
# Gets an inexed parameter of the projection.
|
939
|
+
|
940
|
+
def get_parameter(index_)
|
941
|
+
@parameters[index_]
|
942
|
+
end
|
943
|
+
|
944
|
+
|
945
|
+
# Iterates over the parameters of the projection.
|
946
|
+
|
947
|
+
def each_parameter(&block_)
|
948
|
+
@parameters.each(&block_)
|
949
|
+
end
|
950
|
+
|
951
|
+
|
952
|
+
def _wkt_typename # :nodoc:
|
953
|
+
"PROJECTION"
|
954
|
+
end
|
955
|
+
|
956
|
+
def _wkt_content(open_, close_) # :nodoc:
|
957
|
+
[]
|
958
|
+
end
|
959
|
+
|
960
|
+
|
961
|
+
class << self
|
962
|
+
|
963
|
+
|
964
|
+
# Create a Projection given a name, a projection class, and an
|
965
|
+
# array of ProjectionParameter. You may also provide the
|
966
|
+
# optional parameters specified by the Info interface.
|
967
|
+
|
968
|
+
def create(name_, class_name_, parameters_, *optional_)
|
969
|
+
new(name_, class_name_, parameters_, *optional_)
|
970
|
+
end
|
971
|
+
|
972
|
+
|
973
|
+
end
|
974
|
+
|
975
|
+
end
|
976
|
+
|
977
|
+
|
978
|
+
# == OGC spec description
|
979
|
+
#
|
980
|
+
# Base interface for all coordinate systems.
|
981
|
+
#
|
982
|
+
# A coordinate system is a mathematical space, where the elements
|
983
|
+
# of the space are called positions. Each position is described by
|
984
|
+
# a list of numbers. The length of the list corresponds to the
|
985
|
+
# dimension of the coordinate system. So in a 2D coordinate system
|
986
|
+
# each position is described by a list containing 2 numbers.
|
987
|
+
#
|
988
|
+
# However, in a coordinate system, not all lists of numbers
|
989
|
+
# correspond to a position -- some lists may be outside the domain
|
990
|
+
# of the coordinate system. For example, in a 2D Lat/Lon coordinate
|
991
|
+
# system, the list (91,91) does not correspond to a position.
|
992
|
+
#
|
993
|
+
# Some coordinate systems also have a mapping from the mathematical
|
994
|
+
# space into locations in the real world. So in a Lat/Lon coordinate
|
995
|
+
# system, the mathematical position (lat, long) corresponds to a
|
996
|
+
# location on the surface of the Earth. This mapping from the
|
997
|
+
# mathematical space into real-world locations is called a Datum.
|
998
|
+
#
|
999
|
+
# == Notes
|
1000
|
+
#
|
1001
|
+
# This is a non-instantiable abstract class. You must instantiate
|
1002
|
+
# one of the subclasses GeocentricCoordinateSystem,
|
1003
|
+
# GeographicCoordinateSystem, ProjectedCoordinateSystem,
|
1004
|
+
# VerticalCoordinateSystem, LocalCoordinateSystem, or
|
1005
|
+
# CompoundCoordinateSystem.
|
1006
|
+
|
1007
|
+
class CoordinateSystem < Info
|
1008
|
+
|
1009
|
+
def initialize(name_, dimension_, *optional_) # :nodoc:
|
1010
|
+
super(name_, *optional_)
|
1011
|
+
@dimension = dimension_.to_i
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
|
1015
|
+
# Dimension of the coordinate system
|
1016
|
+
attr_reader :dimension
|
1017
|
+
|
1018
|
+
|
1019
|
+
# Gets axis details for dimension within coordinate system. Each
|
1020
|
+
# dimension in the coordinate system has a corresponding axis.
|
1021
|
+
|
1022
|
+
def get_axis(dimension_)
|
1023
|
+
nil
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
|
1027
|
+
# Gets units for dimension within coordinate system. Each
|
1028
|
+
# dimension in the coordinate system has corresponding units.
|
1029
|
+
|
1030
|
+
def get_units(dimension_)
|
1031
|
+
nil
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
|
1038
|
+
# == OGC spec description
|
1039
|
+
#
|
1040
|
+
# An aggregate of two coordinate systems (CRS). One of these is
|
1041
|
+
# usually a CRS based on a two dimensional coordinate system such
|
1042
|
+
# as a geographic or a projected coordinate system with a horizontal
|
1043
|
+
# datum. The other is a vertical CRS which is a one-dimensional
|
1044
|
+
# coordinate system with a vertical datum.
|
1045
|
+
|
1046
|
+
class CompoundCoordinateSystem < CoordinateSystem
|
1047
|
+
|
1048
|
+
def initialize(name_, head_, tail_, *optional_) # :nodoc:
|
1049
|
+
super(name_, head_.dimension + tail_.dimension, *optional_)
|
1050
|
+
@head = head_
|
1051
|
+
@tail = tail_
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
|
1055
|
+
# Gets first sub-coordinate system.
|
1056
|
+
attr_reader :head
|
1057
|
+
|
1058
|
+
# Gets second sub-coordinate system.
|
1059
|
+
attr_reader :tail
|
1060
|
+
|
1061
|
+
|
1062
|
+
# Implements CoordinateSystem#get_axis
|
1063
|
+
|
1064
|
+
def get_axis(index_)
|
1065
|
+
hd_ = @head.dimension
|
1066
|
+
index_ < hd_ ? @head.get_axis(index_) : @tail.get_axis(index_ - hd_)
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
|
1070
|
+
# Implements CoordinateSystem#get_units
|
1071
|
+
|
1072
|
+
def get_units(index_)
|
1073
|
+
hd_ = @head.dimension
|
1074
|
+
index_ < hd_ ? @head.get_units(index_) : @tail.get_units(index_ - hd_)
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
|
1078
|
+
def _wkt_typename # :nodoc:
|
1079
|
+
"COMPD_CS"
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1083
|
+
[@head._to_wkt(open_, close_), @tail._to_wkt(open_, close_)]
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
|
1087
|
+
class << self
|
1088
|
+
|
1089
|
+
|
1090
|
+
# Create a CompoundCoordinateSystem given two sub-coordinate
|
1091
|
+
# systems. You may also provide the optional parameters
|
1092
|
+
# specified by the Info interface.
|
1093
|
+
|
1094
|
+
def create(name_, head_, tail_, *optional_)
|
1095
|
+
new(name_, head_, tail_, *optional_)
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
|
1105
|
+
# == OGC spec description
|
1106
|
+
#
|
1107
|
+
# A local coordinate system, with uncertain relationship to the
|
1108
|
+
# world. In general, a local coordinate system cannot be related to
|
1109
|
+
# other coordinate systems. However, if two objects supporting this
|
1110
|
+
# interface have the same dimension, axes, units and datum then
|
1111
|
+
# client code is permitted to assume that the two coordinate systems
|
1112
|
+
# are identical. This allows several datasets from a common source
|
1113
|
+
# (e.g. a CAD system) to be overlaid. In addition, some
|
1114
|
+
# implementations of the Coordinate Transformation (CT) package may
|
1115
|
+
# have a mechanism for correlating local datums. (E.g. from a
|
1116
|
+
# database of transformations, which is created and maintained from
|
1117
|
+
# real-world measurements.)
|
1118
|
+
#
|
1119
|
+
# == Notes
|
1120
|
+
#
|
1121
|
+
# RGeo's implementation does not provide the Coordinate
|
1122
|
+
# Transformation (CT) package.
|
1123
|
+
|
1124
|
+
class LocalCoordinateSystem < CoordinateSystem
|
1125
|
+
|
1126
|
+
def initialize(name_, local_datum_, unit_, axes_, *optional_) # :nodoc:
|
1127
|
+
super(name_, axes_.size, *optional_)
|
1128
|
+
@local_datum = local_datum_
|
1129
|
+
@unit = unit_
|
1130
|
+
@axes = axes_.dup
|
1131
|
+
end
|
1132
|
+
|
1133
|
+
|
1134
|
+
# Gets the local datum.
|
1135
|
+
attr_reader :local_datum
|
1136
|
+
|
1137
|
+
|
1138
|
+
# Implements CoordinateSystem#get_axis
|
1139
|
+
|
1140
|
+
def get_axis(index_)
|
1141
|
+
@axes[index_]
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
|
1145
|
+
# Implements CoordinateSystem#get_units
|
1146
|
+
|
1147
|
+
def get_units(index_)
|
1148
|
+
@unit
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
|
1152
|
+
def _wkt_typename # :nodoc:
|
1153
|
+
"LOCAL_CS"
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1157
|
+
[@local_datum._to_wkt(open_, close_), @unit._to_wkt(open_, close_)] + @axes.map{ |ax_| ax_._to_wkt(open_, close_) }
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
|
1161
|
+
class << self
|
1162
|
+
|
1163
|
+
|
1164
|
+
# Create a LocalCoordinateSystem given a name, a LocalDatum, a
|
1165
|
+
# Unit, and an array of at least one AxisInfo. You may also
|
1166
|
+
# provide the optional parameters specified by the Info
|
1167
|
+
# interface.
|
1168
|
+
|
1169
|
+
def create(name_, local_datum_, unit_, axes_, *optional_)
|
1170
|
+
new(name_, local_datum_, unit_, axes_, *optional_)
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
|
1179
|
+
# == OGC spec description
|
1180
|
+
#
|
1181
|
+
# A 3D coordinate system, with its origin at the centre of the
|
1182
|
+
# Earth. The X axis points towards the prime meridian. The Y axis
|
1183
|
+
# points East or West. The Z axis points North or South. By default
|
1184
|
+
# the Z axis will point North, and the Y axis will point East (e.g.
|
1185
|
+
# a right handed system), but you should check the axes for
|
1186
|
+
# non-default values.
|
1187
|
+
|
1188
|
+
class GeocentricCoordinateSystem < CoordinateSystem
|
1189
|
+
|
1190
|
+
def initialize(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_) # :nodoc:
|
1191
|
+
super(name_, 3, *optional_)
|
1192
|
+
@horizontal_datum = horizontal_datum_
|
1193
|
+
@prime_meridian = prime_meridian_
|
1194
|
+
@linear_unit = linear_unit_
|
1195
|
+
@axis0 = axis0_
|
1196
|
+
@axis1 = axis1_
|
1197
|
+
@axis2 = axis2_
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
|
1201
|
+
# Returns the HorizontalDatum. The horizontal datum is used to
|
1202
|
+
# determine where the centre of the Earth is considered to be.
|
1203
|
+
# All coordinate points will be measured from the centre of the
|
1204
|
+
# Earth, and not the surface.
|
1205
|
+
attr_reader :horizontal_datum
|
1206
|
+
|
1207
|
+
# Returns the PrimeMeridian.
|
1208
|
+
attr_reader :prime_meridian
|
1209
|
+
|
1210
|
+
# Gets the units used along all the axes.
|
1211
|
+
attr_reader :linear_unit
|
1212
|
+
|
1213
|
+
|
1214
|
+
# Implements CoordinateSystem#get_units
|
1215
|
+
|
1216
|
+
def get_units(index_)
|
1217
|
+
@linear_unit
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
|
1221
|
+
# Implements CoordinateSystem#get_axis
|
1222
|
+
|
1223
|
+
def get_axis(index_)
|
1224
|
+
[@axis0, @axis1, @axis2][index_]
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
|
1228
|
+
def _wkt_typename # :nodoc:
|
1229
|
+
"GEOCCS"
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1233
|
+
arr_ = [@horizontal_datum._to_wkt(open_, close_), @prime_meridian._to_wkt(open_, close_), @linear_unit._to_wkt(open_, close_)]
|
1234
|
+
arr_ << @axis0._to_wkt(open_, close_) if @axis0
|
1235
|
+
arr_ << @axis1._to_wkt(open_, close_) if @axis1
|
1236
|
+
arr_ << @axis2._to_wkt(open_, close_) if @axis2
|
1237
|
+
arr_
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
|
1241
|
+
class << self
|
1242
|
+
|
1243
|
+
|
1244
|
+
# Create a GeocentricCoordinateSystem given a name, a
|
1245
|
+
# HorizontalDatum, a PrimeMeridian, a LinearUnit, and three
|
1246
|
+
# AxisInfo objects. The AxisInfo are optional and may be nil.
|
1247
|
+
# You may also provide the optional parameters specified by the
|
1248
|
+
# Info interface.
|
1249
|
+
|
1250
|
+
def create(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
|
1251
|
+
new(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
|
1261
|
+
# == OGC spec description
|
1262
|
+
#
|
1263
|
+
# A one-dimensional coordinate system suitable for vertical
|
1264
|
+
# measurements.
|
1265
|
+
|
1266
|
+
class VerticalCoordinateSystem < CoordinateSystem
|
1267
|
+
|
1268
|
+
def initialize(name_, vertical_datum_, vertical_unit_, axis_, *optional_) # :nodoc:
|
1269
|
+
super(name_, 1, *optional_)
|
1270
|
+
@vertical_datum = vertical_datum_
|
1271
|
+
@vertical_unit = vertical_unit_
|
1272
|
+
@axis = axis_
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
|
1276
|
+
# Gets the vertical datum, which indicates the measurement method.
|
1277
|
+
attr_reader :vertical_datum
|
1278
|
+
|
1279
|
+
# Gets the units used along the vertical axis. The vertical units
|
1280
|
+
# must be the same as the CS_CoordinateSystem units.
|
1281
|
+
attr_reader :vertical_unit
|
1282
|
+
|
1283
|
+
|
1284
|
+
# Implements CoordinateSystem#get_units
|
1285
|
+
|
1286
|
+
def get_units(index_)
|
1287
|
+
@vertical_unit
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
|
1291
|
+
# Implements CoordinateSystem#get_axis
|
1292
|
+
|
1293
|
+
def get_axis(index_)
|
1294
|
+
@axis
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
|
1298
|
+
def _wkt_typename # :nodoc:
|
1299
|
+
"VERT_CS"
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1303
|
+
arr_ = [@vertical_datum._to_wkt(open_, close_), @vertical_unit._to_wkt(open_, close_)]
|
1304
|
+
arr_ << @axis._to_wkt(open_, close_) if @axis
|
1305
|
+
arr_
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
|
1309
|
+
class << self
|
1310
|
+
|
1311
|
+
|
1312
|
+
# Create a VerticalCoordinateSystem given a name, a
|
1313
|
+
# VerticalDatum, a LinearUnit, and an AxisInfo. The AxisInfo is
|
1314
|
+
# optional and may be nil. You may also provide the optional
|
1315
|
+
# parameters specified by the Info interface.
|
1316
|
+
|
1317
|
+
def create(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
|
1318
|
+
new(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
|
1319
|
+
end
|
1320
|
+
|
1321
|
+
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
|
1328
|
+
# == OGC spec description
|
1329
|
+
#
|
1330
|
+
# A 2D coordinate system suitable for positions on the Earth's surface.
|
1331
|
+
#
|
1332
|
+
# == Notes
|
1333
|
+
#
|
1334
|
+
# This is a non-instantiable abstract class. You must instantiate
|
1335
|
+
# one of the subclasses GeographicCoordinateSystem or
|
1336
|
+
# ProjectedCoordinateSystem.
|
1337
|
+
|
1338
|
+
class HorizontalCoordinateSystem < CoordinateSystem
|
1339
|
+
|
1340
|
+
def initialize(name_, horizontal_datum_, *optional_) # :nodoc:
|
1341
|
+
super(name_, 2, *optional_)
|
1342
|
+
@horizontal_datum = horizontal_datum_
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
|
1346
|
+
# Returns the HorizontalDatum.
|
1347
|
+
attr_reader :horizontal_datum
|
1348
|
+
|
1349
|
+
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
|
1353
|
+
# == OGC spec description
|
1354
|
+
#
|
1355
|
+
# A coordinate system based on latitude and longitude. Some
|
1356
|
+
# geographic coordinate systems are Lat/Lon, and some are Lon/Lat.
|
1357
|
+
# You can find out which this is by examining the axes. You should
|
1358
|
+
# also check the angular units, since not all geographic coordinate
|
1359
|
+
# systems use degrees.
|
1360
|
+
|
1361
|
+
class GeographicCoordinateSystem < HorizontalCoordinateSystem
|
1362
|
+
|
1363
|
+
def initialize(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_) # :nodoc:
|
1364
|
+
super(name_, horizontal_datum_, *optional_)
|
1365
|
+
@prime_meridian = prime_meridian_
|
1366
|
+
@angular_unit = angular_unit_
|
1367
|
+
@axis0 = axis0_
|
1368
|
+
@axis1 = axis1_
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
|
1372
|
+
# Returns the PrimeMeridian.
|
1373
|
+
attr_reader :prime_meridian
|
1374
|
+
|
1375
|
+
# Returns the AngularUnit. The angular unit must be the same as
|
1376
|
+
# the CS_CoordinateSystem units.
|
1377
|
+
attr_reader :angular_unit
|
1378
|
+
|
1379
|
+
|
1380
|
+
# Implements CoordinateSystem#get_units
|
1381
|
+
|
1382
|
+
def get_units(index_)
|
1383
|
+
@angular_unit
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
|
1387
|
+
# Implements CoordinateSystem#get_axis
|
1388
|
+
|
1389
|
+
def get_axis(index_)
|
1390
|
+
index_ == 1 ? @axis1 : @axis0
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
|
1394
|
+
# Gets the number of available conversions to WGS84 coordinates.
|
1395
|
+
|
1396
|
+
def num_conversion_to_wgs84
|
1397
|
+
@horizontal_datum.wgs84_parameters ? 1 : 0
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
|
1401
|
+
# Gets details on a conversion to WGS84. Some geographic
|
1402
|
+
# coordinate systems provide several transformations into WGS84,
|
1403
|
+
# which are designed to provide good accuracy in different areas
|
1404
|
+
# of interest. The first conversion (with index=0) should provide
|
1405
|
+
# acceptable accuracy over the largest possible area of interest.
|
1406
|
+
|
1407
|
+
def get_wgs84_conversion_info(index_)
|
1408
|
+
@horizontal_datum.wgs84_parameters
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
|
1412
|
+
def _wkt_typename # :nodoc:
|
1413
|
+
"GEOGCS"
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1417
|
+
arr_ = [@horizontal_datum._to_wkt(open_, close_), @prime_meridian._to_wkt(open_, close_), @angular_unit._to_wkt(open_, close_)]
|
1418
|
+
arr_ << @axis0._to_wkt(open_, close_) if @axis0
|
1419
|
+
arr_ << @axis1._to_wkt(open_, close_) if @axis1
|
1420
|
+
arr_
|
1421
|
+
end
|
1422
|
+
|
1423
|
+
|
1424
|
+
class << self
|
1425
|
+
|
1426
|
+
|
1427
|
+
# Create a GeographicCoordinateSystem, given a name, an
|
1428
|
+
# AngularUnit, a HorizontalDatum, a PrimeMeridian, and two
|
1429
|
+
# AxisInfo objects. The AxisInfo objects are optional and may
|
1430
|
+
# be set to nil. You may also provide the optional parameters
|
1431
|
+
# specified by the Info interface.
|
1432
|
+
|
1433
|
+
def create(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
|
1434
|
+
new(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
|
1435
|
+
end
|
1436
|
+
|
1437
|
+
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
|
1441
|
+
end
|
1442
|
+
|
1443
|
+
|
1444
|
+
# == OGC spec description
|
1445
|
+
#
|
1446
|
+
# A 2D cartographic coordinate system.
|
1447
|
+
|
1448
|
+
class ProjectedCoordinateSystem < HorizontalCoordinateSystem
|
1449
|
+
|
1450
|
+
def initialize(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_) # :nodoc:
|
1451
|
+
super(name_, geographic_coordinate_system_.horizontal_datum, *optional_)
|
1452
|
+
@geographic_coordinate_system = geographic_coordinate_system_
|
1453
|
+
@projection = projection_
|
1454
|
+
@linear_unit = linear_unit_
|
1455
|
+
@axis0 = axis0_
|
1456
|
+
@axis1 = axis1_
|
1457
|
+
end
|
1458
|
+
|
1459
|
+
|
1460
|
+
# Returns the GeographicCoordinateSystem.
|
1461
|
+
attr_reader :geographic_coordinate_system
|
1462
|
+
|
1463
|
+
# Gets the projection.
|
1464
|
+
attr_reader :projection
|
1465
|
+
|
1466
|
+
# Returns the LinearUnits. The linear unit must be the same as
|
1467
|
+
# the CS_CoordinateSystem units.
|
1468
|
+
attr_reader :linear_unit
|
1469
|
+
|
1470
|
+
|
1471
|
+
# Implements CoordinateSystem#get_units
|
1472
|
+
|
1473
|
+
def get_units(index_)
|
1474
|
+
@linear_unit
|
1475
|
+
end
|
1476
|
+
|
1477
|
+
|
1478
|
+
# Implements CoordinateSystem#get_axis
|
1479
|
+
|
1480
|
+
def get_axis(index_)
|
1481
|
+
index_ == 1 ? @axis1 : @axis0
|
1482
|
+
end
|
1483
|
+
|
1484
|
+
|
1485
|
+
def _wkt_typename # :nodoc:
|
1486
|
+
"PROJCS"
|
1487
|
+
end
|
1488
|
+
|
1489
|
+
def _wkt_content(open_, close_) # :nodoc:
|
1490
|
+
arr_ = [@geographic_coordinate_system._to_wkt(open_, close_), @projection._to_wkt(open_, close_)]
|
1491
|
+
@projection.each_parameter{ |param_| arr_ << param_._to_wkt(open_, close_) }
|
1492
|
+
arr_ << @linear_unit._to_wkt(open_, close_)
|
1493
|
+
arr_ << @axis0._to_wkt(open_, close_) if @axis0
|
1494
|
+
arr_ << @axis1._to_wkt(open_, close_) if @axis1
|
1495
|
+
arr_
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
|
1499
|
+
class << self
|
1500
|
+
|
1501
|
+
|
1502
|
+
# Create a ProjectedCoordinateSystem given a name, a
|
1503
|
+
# GeographicCoordinateSystem, and Projection, a LinearUnit, and
|
1504
|
+
# two AxisInfo objects. The AxisInfo objects are optional and
|
1505
|
+
# may be set to nil. You may also provide the optional
|
1506
|
+
# parameters specified by the Info interface.
|
1507
|
+
|
1508
|
+
def create(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
|
1509
|
+
new(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
|
1510
|
+
end
|
1511
|
+
|
1512
|
+
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
|
1516
|
+
end
|
1517
|
+
|
1518
|
+
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
end
|