rgeo 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +8 -0
- data/README.rdoc +2 -2
- data/Version +1 -1
- data/lib/rgeo/cartesian/factory.rb +10 -1
- data/lib/rgeo/cartesian/interface.rb +46 -2
- data/lib/rgeo/coord_sys/cs/entities.rb +758 -39
- data/lib/rgeo/coord_sys/cs/factories.rb +82 -12
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +1 -0
- data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +83 -1
- data/lib/rgeo/coord_sys/srs_database/interface.rb +53 -0
- data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +60 -15
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +20 -0
- data/lib/rgeo/coord_sys/srs_database/url_reader.rb +18 -0
- data/lib/rgeo/feature/factory_generator.rb +17 -4
- data/lib/rgeo/geographic/factory.rb +5 -1
- data/lib/rgeo/geographic/interface.rb +205 -71
- data/lib/rgeo/geographic/proj4_projector.rb +1 -1
- data/lib/rgeo/geographic/simple_mercator_projector.rb +17 -1
- data/lib/rgeo/geos/factory.rb +10 -1
- data/lib/rgeo/geos/interface.rb +26 -0
- data/lib/rgeo/geos/zm_factory.rb +18 -2
- data/test/coord_sys/tc_active_record_table.rb +8 -3
- metadata +3 -3
data/History.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.2.3 / 2010-12-19
|
2
|
+
|
3
|
+
* The "simpler mercator" geographic type incorrectly reported EPSG 3857 instead of EPSG 3785 for the projection. Dyslexia fixed.
|
4
|
+
* Geographic types couldn't have their coord_sys set. Fixed.
|
5
|
+
* You can now pass an :srs_database option when creating most factory types. This lets the factory look up its coordinate system using the given SRID.
|
6
|
+
* There are now explicit methods you can call to obtain FactoryGenerator objects; you should not need to call <tt>method</tt>.
|
7
|
+
* Wrote RDocs for all the CoordSys::CS and CoordSys::SRSDatabase classes.
|
8
|
+
|
1
9
|
=== 0.2.2 / 2010-12-15
|
2
10
|
|
3
11
|
The main theme for this release was support for spatial reference system databases. The basic functionality is done and ready for experimentation. However, documentation is still in progress, and we're still working on some ideas to make coordinate system management more seamless by integrating the SRS databases with FactoryGenerator.
|
data/README.rdoc
CHANGED
@@ -47,7 +47,7 @@ RGeo is known to work with the following Ruby implementations:
|
|
47
47
|
* Rubinius 1.1 or later.
|
48
48
|
* Partial support for JRuby 1.5 or later, but a bunch of features are
|
49
49
|
missing because GEOS and Proj are not available from Java. We plan on
|
50
|
-
integrating with JTS in the future.
|
50
|
+
integrating with JTS or possibly ffi-geos in the future.
|
51
51
|
|
52
52
|
Some features also require the following:
|
53
53
|
|
@@ -107,7 +107,7 @@ The RGeo suite of tools is evolving rapidly. The current to-do list for
|
|
107
107
|
the core library includes:
|
108
108
|
|
109
109
|
* Ellipsoidal geography implementation, possibly utilizing geographiclib.
|
110
|
-
* JRuby support via the JTS library.
|
110
|
+
* JRuby support via the JTS library, or possibly via ffi-geos.
|
111
111
|
* Windows build support.
|
112
112
|
|
113
113
|
Each of the current add-on modules also has its own feature roadmap, and
|
data/Version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
@@ -52,7 +52,6 @@ module RGeo
|
|
52
52
|
# See ::RGeo::Cartesian::simple_factory for a list of supported options.
|
53
53
|
|
54
54
|
def initialize(opts_={})
|
55
|
-
@srid = opts_[:srid].to_i
|
56
55
|
@has_z = opts_[:has_z_coordinate] ? true : false
|
57
56
|
@has_m = opts_[:has_m_coordinate] ? true : false
|
58
57
|
@proj4 = opts_[:proj4]
|
@@ -63,10 +62,20 @@ module RGeo
|
|
63
62
|
else
|
64
63
|
@proj4 = nil
|
65
64
|
end
|
65
|
+
srid_ = opts_[:srid]
|
66
66
|
@coord_sys = opts_[:coord_sys]
|
67
67
|
if @coord_sys.kind_of?(::String)
|
68
68
|
@coord_sys = CoordSys::CS.create_from_wkt(@coord_sys) rescue nil
|
69
69
|
end
|
70
|
+
if (!@proj4 || !@coord_sys) && srid_ && (db_ = opts_[:srs_database])
|
71
|
+
entry_ = db_.get(srid_.to_i)
|
72
|
+
if entry_
|
73
|
+
@proj4 ||= entry_.proj4
|
74
|
+
@coord_sys ||= entry_.coord_sys
|
75
|
+
end
|
76
|
+
end
|
77
|
+
srid_ ||= @coord_sys.authority_code if @coord_sys
|
78
|
+
@srid = srid_.to_i
|
70
79
|
end
|
71
80
|
|
72
81
|
|
@@ -49,10 +49,13 @@ module RGeo
|
|
49
49
|
# RGeo will try to provide a fully-functional and performant
|
50
50
|
# implementation if possible. If not, the simple Cartesian
|
51
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.
|
52
54
|
#
|
53
55
|
# The given options are passed to the factory's constructor.
|
54
56
|
# What options are available depends on the particular
|
55
|
-
# implementation.
|
57
|
+
# implementation. See Geos::factory and Cartesian::simple_factory
|
58
|
+
# for details. Unsupported options are ignored.
|
56
59
|
|
57
60
|
def preferred_factory(opts_={})
|
58
61
|
if ::RGeo::Geos.supported?
|
@@ -82,13 +85,27 @@ module RGeo
|
|
82
85
|
# not all types.
|
83
86
|
# * Assertions for polygons and multipolygons are not implemented.
|
84
87
|
#
|
85
|
-
# Unimplemented operations
|
88
|
+
# Unimplemented operations may raise Error::UnsupportedOperation
|
89
|
+
# if invoked.
|
86
90
|
#
|
87
91
|
# Options include:
|
88
92
|
#
|
89
93
|
# <tt>:srid</tt>::
|
90
94
|
# Set the SRID returned by geometries created by this factory.
|
91
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.
|
92
109
|
# <tt>:has_z_coordinate</tt>::
|
93
110
|
# Support a Z coordinate. Default is false.
|
94
111
|
# <tt>:has_m_coordinate</tt>::
|
@@ -99,6 +116,33 @@ module RGeo
|
|
99
116
|
end
|
100
117
|
|
101
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
|
+
|
102
146
|
end
|
103
147
|
|
104
148
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
# -----------------------------------------------------------------------------
|
2
3
|
#
|
3
4
|
# OGC CS objects for RGeo
|
@@ -42,57 +43,174 @@ module RGeo
|
|
42
43
|
module CS
|
43
44
|
|
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.
|
45
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.
|
46
54
|
AO_NORTH = 1
|
55
|
+
|
56
|
+
# An axis orientation constant for AxisInfo.
|
57
|
+
# Increasing ordinates values go South. This is rarely used.
|
47
58
|
AO_SOUTH = 2
|
59
|
+
|
60
|
+
# An axis orientation constant for AxisInfo.
|
61
|
+
# Increasing ordinates values go East. This is rarely used.
|
48
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.
|
49
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.
|
50
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.
|
51
77
|
AO_DOWN = 6
|
52
78
|
|
79
|
+
|
80
|
+
# A datum type constant for HorizontalDatum.
|
81
|
+
# Lowest possible value for horizontal datum types.
|
53
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.
|
54
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.
|
55
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.
|
56
105
|
HD_GEOCENTRIC = 1002
|
106
|
+
|
107
|
+
# A datum type constant for HorizontalDatum.
|
108
|
+
# Highest possible value for horizontal datum types.
|
57
109
|
HD_MAX = 1999
|
110
|
+
|
111
|
+
# A datum type constant for VerticalDatum.
|
112
|
+
# Lowest possible value for vertical datum types.
|
58
113
|
VD_MIN = 2000
|
114
|
+
|
115
|
+
# A datum type constant for VerticalDatum.
|
116
|
+
# Unspecified vertical datum type.
|
59
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.
|
60
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.
|
61
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).
|
62
137
|
VD_ALTITUDE_BAROMETRIC = 2003
|
138
|
+
|
139
|
+
# A datum type constant for VerticalDatum.
|
140
|
+
# A normal height system.
|
63
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.
|
64
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.
|
65
158
|
VD_DEPTH = 2006
|
159
|
+
|
160
|
+
# A datum type constant for VerticalDatum.
|
161
|
+
# Highest possible value for vertical datum types.
|
66
162
|
VD_MAX = 2999
|
163
|
+
|
164
|
+
# A datum type constant for LocalDatum.
|
165
|
+
# Lowest possible value for local datum types.
|
67
166
|
LD_MIN = 10000
|
167
|
+
|
168
|
+
# A datum type constant for LocalDatum.
|
169
|
+
# Highest possible value for local datum types.
|
68
170
|
LD_MAX = 32767
|
69
171
|
|
70
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
|
+
|
71
179
|
class Base
|
72
180
|
|
73
|
-
def initialize(name_) # :nodoc:
|
74
|
-
@name = name_.to_s
|
75
|
-
end
|
76
|
-
|
77
|
-
attr_reader :name
|
78
181
|
|
79
|
-
def inspect
|
182
|
+
def inspect # :nodoc:
|
80
183
|
"#<#{self.class}:0x#{object_id.to_s(16)} #{to_wkt}>"
|
81
184
|
end
|
82
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
|
+
|
83
190
|
def eql?(rhs_)
|
84
191
|
rhs_.class == self.class && rhs_.to_wkt == self.to_wkt
|
85
192
|
end
|
86
193
|
alias_method :==, :eql?
|
87
194
|
|
195
|
+
|
196
|
+
# Returns the default WKT representation.
|
197
|
+
|
88
198
|
def to_s
|
89
199
|
to_wkt
|
90
200
|
end
|
91
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
|
+
|
92
209
|
def to_wkt(opts_={})
|
93
210
|
opts_[:standard_brackets] ? _to_wkt('(', ')') : _to_wkt('[', ']')
|
94
211
|
end
|
95
212
|
|
213
|
+
|
96
214
|
def _to_wkt(open_, close_) # :nodoc:
|
97
215
|
content_ = _wkt_content(open_, close_).map{ |obj_| ",#{obj_}" }.join
|
98
216
|
if defined?(@authority) && @authority
|
@@ -103,30 +221,47 @@ module RGeo
|
|
103
221
|
"#{_wkt_typename}#{open_}#{@name.inspect}#{content_}#{authority_}#{close_}"
|
104
222
|
end
|
105
223
|
|
224
|
+
|
106
225
|
class << self
|
107
226
|
|
108
227
|
private :new
|
109
228
|
|
110
229
|
end
|
111
230
|
|
231
|
+
|
112
232
|
end
|
113
233
|
|
114
234
|
|
235
|
+
# == OGC spec description
|
236
|
+
#
|
237
|
+
# Details of axis. This is used to label axes, and indicate the
|
238
|
+
# orientation.
|
239
|
+
|
115
240
|
class AxisInfo < Base
|
116
241
|
|
242
|
+
# :stopdoc:
|
117
243
|
NAMES_BY_VALUE = ['OTHER', 'NORTH', 'SOUTH', 'EAST', 'WEST', 'UP', 'DOWN']
|
244
|
+
# :startdoc:
|
118
245
|
|
119
246
|
def initialize(name_, orientation_) # :nodoc:
|
120
|
-
|
121
|
-
|
122
|
-
|
247
|
+
@name = name_
|
248
|
+
case orientation_
|
249
|
+
when ::String, ::Symbol
|
250
|
+
@orientation = NAMES_BY_VALUE.index(orientation_.to_s.upcase).to_i
|
123
251
|
else
|
124
252
|
@orientation = orientation_.to_i
|
125
253
|
end
|
126
254
|
end
|
127
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.
|
128
262
|
attr_reader :orientation
|
129
263
|
|
264
|
+
|
130
265
|
def _wkt_typename # :nodoc:
|
131
266
|
"AXIS"
|
132
267
|
end
|
@@ -135,26 +270,51 @@ module RGeo
|
|
135
270
|
[NAMES_BY_VALUE[@orientation]]
|
136
271
|
end
|
137
272
|
|
273
|
+
|
138
274
|
class << self
|
139
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
|
+
|
140
285
|
def create(name_, orientation_)
|
141
286
|
new(name_, orientation_)
|
142
287
|
end
|
143
288
|
|
289
|
+
|
144
290
|
end
|
145
291
|
|
146
292
|
end
|
147
293
|
|
148
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
|
+
|
149
303
|
class ProjectionParameter < Base
|
150
304
|
|
151
305
|
def initialize(name_, value_) # :nodoc:
|
152
|
-
|
306
|
+
@name = name_
|
153
307
|
@value = value_.to_f
|
154
308
|
end
|
155
309
|
|
310
|
+
|
311
|
+
# The parameter name.
|
312
|
+
attr_reader :name
|
313
|
+
|
314
|
+
# The parameter value.
|
156
315
|
attr_reader :value
|
157
316
|
|
317
|
+
|
158
318
|
def _wkt_typename # :nodoc:
|
159
319
|
"PARAMETER"
|
160
320
|
end
|
@@ -163,21 +323,32 @@ module RGeo
|
|
163
323
|
[@value]
|
164
324
|
end
|
165
325
|
|
326
|
+
|
166
327
|
class << self
|
167
328
|
|
329
|
+
|
330
|
+
# Create a parameter given the name and value.
|
331
|
+
|
168
332
|
def create(name_, value_)
|
169
333
|
new(name_, value_)
|
170
334
|
end
|
171
335
|
|
336
|
+
|
172
337
|
end
|
173
338
|
|
174
339
|
end
|
175
340
|
|
176
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
|
+
|
177
349
|
class WGS84ConversionInfo < Base
|
178
350
|
|
179
351
|
def initialize(dx_, dy_, dz_, ex_, ey_, ez_, ppm_) # :nodoc:
|
180
|
-
super('TOWGS84')
|
181
352
|
@dx = dx_.to_f
|
182
353
|
@dy = dy_.to_f
|
183
354
|
@dz = dz_.to_f
|
@@ -187,33 +358,94 @@ module RGeo
|
|
187
358
|
@ppm = ppm_.to_f
|
188
359
|
end
|
189
360
|
|
361
|
+
|
362
|
+
# Bursa Wolf shift in meters.
|
190
363
|
attr_reader :dx
|
364
|
+
|
365
|
+
# Bursa Wolf shift in meters.
|
191
366
|
attr_reader :dy
|
367
|
+
|
368
|
+
# Bursa Wolf shift in meters.
|
192
369
|
attr_reader :dz
|
370
|
+
|
371
|
+
# Bursa Wolf rotation in arc seconds.
|
193
372
|
attr_reader :ex
|
373
|
+
|
374
|
+
# Bursa Wolf rotation in arc seconds.
|
194
375
|
attr_reader :ey
|
376
|
+
|
377
|
+
# Bursa Wolf rotation in arc seconds.
|
195
378
|
attr_reader :ez
|
379
|
+
|
380
|
+
# Bursa Wolf scaling in in parts per million.
|
196
381
|
attr_reader :ppm
|
197
382
|
|
383
|
+
|
198
384
|
def _to_wkt(open_, close_) # :nodoc:
|
199
385
|
"TOWGS84#{open_}#{@dx},#{@dy},#{@dz},#{@ex},#{@ey},#{@ez},#{@ppm}#{close_}"
|
200
386
|
end
|
201
387
|
|
388
|
+
|
202
389
|
class << self
|
203
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
|
+
|
204
397
|
def create(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
|
205
398
|
new(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
|
206
399
|
end
|
207
400
|
|
401
|
+
|
208
402
|
end
|
209
403
|
|
210
404
|
end
|
211
405
|
|
212
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
|
+
|
213
445
|
class Info < Base
|
214
446
|
|
215
447
|
def initialize(name_, authority_=nil, authority_code_=nil, abbreviation_=nil, alias_=nil, remarks_=nil) # :nodoc:
|
216
|
-
|
448
|
+
@name = name_
|
217
449
|
@authority = authority_ ? authority_.to_s : nil
|
218
450
|
@authority_code = authority_code_ ? authority_code_.to_s : nil
|
219
451
|
@abbreviation = abbreviation_ ? abbreviation_.to_s : nil
|
@@ -221,15 +453,51 @@ module RGeo
|
|
221
453
|
@remarks = remarks_ ? remarks_.to_s : nil
|
222
454
|
end
|
223
455
|
|
224
|
-
|
225
|
-
|
456
|
+
|
457
|
+
# Gets the abbreviation.
|
226
458
|
attr_reader :abbreviation
|
459
|
+
|
460
|
+
# Gets the alias.
|
227
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.
|
228
485
|
attr_reader :remarks
|
229
486
|
|
487
|
+
|
230
488
|
end
|
231
489
|
|
232
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
|
+
|
233
501
|
class Unit < Info
|
234
502
|
|
235
503
|
def initialize(name_, conversion_factor_, *optional_) # :nodoc:
|
@@ -237,8 +505,13 @@ module RGeo
|
|
237
505
|
@conversion_factor = conversion_factor_.to_f
|
238
506
|
end
|
239
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.
|
240
512
|
attr_reader :conversion_factor
|
241
513
|
|
514
|
+
|
242
515
|
def _wkt_typename # :nodoc:
|
243
516
|
"UNIT"
|
244
517
|
end
|
@@ -247,47 +520,93 @@ module RGeo
|
|
247
520
|
[@conversion_factor]
|
248
521
|
end
|
249
522
|
|
523
|
+
|
250
524
|
class << self
|
251
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
|
+
|
252
532
|
def create(name_, conversion_factor_, *optional_)
|
253
533
|
new(name_, conversion_factor_, *optional_)
|
254
534
|
end
|
255
535
|
|
536
|
+
|
256
537
|
end
|
257
538
|
|
258
539
|
end
|
259
540
|
|
260
541
|
|
542
|
+
# == OGC spec description
|
543
|
+
#
|
544
|
+
# Definition of linear units.
|
545
|
+
|
261
546
|
class LinearUnit < Unit
|
262
547
|
|
263
|
-
|
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
|
+
|
264
556
|
|
265
557
|
class << self
|
266
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
|
+
|
267
564
|
def create(name_, meters_per_unit_, *optional_)
|
268
565
|
new(name_, meters_per_unit_, *optional_)
|
269
566
|
end
|
270
567
|
|
568
|
+
|
271
569
|
end
|
272
570
|
|
273
571
|
end
|
274
572
|
|
275
573
|
|
574
|
+
# == OGC spec description
|
575
|
+
#
|
576
|
+
# Definition of angular units.
|
577
|
+
|
276
578
|
class AngularUnit < Unit
|
277
579
|
|
278
|
-
|
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
|
+
|
279
588
|
|
280
589
|
class << self
|
281
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
|
+
|
282
596
|
def create(name_, radians_per_unit_, *optional_)
|
283
597
|
new(name_, radians_per_unit_, *optional_)
|
284
598
|
end
|
285
599
|
|
600
|
+
|
286
601
|
end
|
287
602
|
|
288
603
|
end
|
289
604
|
|
290
605
|
|
606
|
+
# == OGC spec description
|
607
|
+
#
|
608
|
+
# A meridian used to take longitude measurements from.
|
609
|
+
|
291
610
|
class PrimeMeridian < Info
|
292
611
|
|
293
612
|
def initialize(name_, angular_unit_, longitude_, *optional_) # :nodoc:
|
@@ -296,9 +615,15 @@ module RGeo
|
|
296
615
|
@longitude = longitude_.to_f
|
297
616
|
end
|
298
617
|
|
618
|
+
|
619
|
+
# Returns the AngularUnits.
|
299
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.
|
300
624
|
attr_reader :longitude
|
301
625
|
|
626
|
+
|
302
627
|
def _wkt_typename # :nodoc:
|
303
628
|
"PRIMEM"
|
304
629
|
end
|
@@ -307,17 +632,30 @@ module RGeo
|
|
307
632
|
[@longitude]
|
308
633
|
end
|
309
634
|
|
635
|
+
|
310
636
|
class << self
|
311
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
|
+
|
312
644
|
def create(name_, angular_unit_, longitude_, *optional_)
|
313
645
|
new(name_, angular_unit_, longitude_, *optional_)
|
314
646
|
end
|
315
647
|
|
648
|
+
|
316
649
|
end
|
317
650
|
|
651
|
+
|
318
652
|
end
|
319
653
|
|
320
654
|
|
655
|
+
# == OGC spec description
|
656
|
+
#
|
657
|
+
# An approximation of the Earth's surface as a squashed sphere.
|
658
|
+
|
321
659
|
class Ellipsoid < Info
|
322
660
|
|
323
661
|
def initialize(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_) # :nodoc:
|
@@ -329,11 +667,32 @@ module RGeo
|
|
329
667
|
@linear_unit = linear_unit_
|
330
668
|
end
|
331
669
|
|
670
|
+
|
671
|
+
# Gets the equatorial radius. The returned length is expressed in
|
672
|
+
# this object's axis units.
|
332
673
|
attr_reader :semi_major_axis
|
674
|
+
|
675
|
+
# Gets the polar radius. The returned length is expressed in this
|
676
|
+
# object's axis units.
|
333
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.
|
334
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.
|
335
690
|
attr_reader :ivf_definitive
|
336
|
-
|
691
|
+
|
692
|
+
# Returns the LinearUnit. The units of the semi-major and
|
693
|
+
# semi-minor axis values.
|
694
|
+
attr_reader :axis_unit
|
695
|
+
|
337
696
|
|
338
697
|
def _wkt_typename # :nodoc:
|
339
698
|
"SPHEROID"
|
@@ -343,33 +702,77 @@ module RGeo
|
|
343
702
|
[@semi_major_axis, @inverse_flattening]
|
344
703
|
end
|
345
704
|
|
346
|
-
def self.create_ellipsoid(name_, semi_major_axis_, semi_minor_axis_, linear_unit_, *optional_)
|
347
|
-
semi_major_axis_ = semi_major_axis_.to_f
|
348
|
-
semi_minor_axis_ = semi_minor_axis_.to_f
|
349
|
-
inverse_flattening_ = semi_major_axis_ / (semi_major_axis_ - semi_minor_axis_)
|
350
|
-
inverse_flattening_ = 0.0 if inverse_flattening_.infinite?
|
351
|
-
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, false, linear_unit_, *optional_)
|
352
|
-
end
|
353
|
-
|
354
|
-
def self.create_flattened_sphere(name_, semi_major_axis_, inverse_flattening_, linear_unit_, *optional_)
|
355
|
-
semi_major_axis_ = semi_major_axis_.to_f
|
356
|
-
inverse_flattening_ = inverse_flattening_.to_f
|
357
|
-
semi_minor_axis_ = semi_major_axis_ - semi_major_axis_ / inverse_flattening_
|
358
|
-
semi_minor_axis_ = semi_major_axis_ if semi_minor_axis_.infinite?
|
359
|
-
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, true, linear_unit_, *optional_)
|
360
|
-
end
|
361
705
|
|
362
706
|
class << self
|
363
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
|
+
|
364
716
|
def create(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
|
365
717
|
new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
|
366
718
|
end
|
367
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
|
+
|
368
751
|
end
|
369
752
|
|
370
753
|
end
|
371
754
|
|
372
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
|
+
|
373
776
|
class Datum < Info
|
374
777
|
|
375
778
|
def initialize(name_, datum_type_, *optional_) # :nodoc:
|
@@ -377,23 +780,23 @@ module RGeo
|
|
377
780
|
@datum_type = datum_type_.to_i
|
378
781
|
end
|
379
782
|
|
783
|
+
|
784
|
+
# Gets the type of the datum as an enumerated code.
|
380
785
|
attr_reader :datum_type
|
381
786
|
|
787
|
+
|
382
788
|
def _wkt_content(open_, close_) # :nodoc:
|
383
789
|
[]
|
384
790
|
end
|
385
791
|
|
386
|
-
class << self
|
387
|
-
|
388
|
-
def create(name_, datum_type_, *optional_)
|
389
|
-
new(name_, datum_type_, *optional_)
|
390
|
-
end
|
391
|
-
|
392
|
-
end
|
393
792
|
|
394
793
|
end
|
395
794
|
|
396
795
|
|
796
|
+
# == OGC spec description
|
797
|
+
#
|
798
|
+
# Procedure used to measure vertical distances.
|
799
|
+
|
397
800
|
class VerticalDatum < Datum
|
398
801
|
|
399
802
|
def _wkt_typename # :nodoc:
|
@@ -406,15 +809,29 @@ module RGeo
|
|
406
809
|
|
407
810
|
class << self
|
408
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
|
+
|
409
817
|
def create(name_, datum_type_, *optional_)
|
410
818
|
new(name_, datum_type_, *optional_)
|
411
819
|
end
|
412
820
|
|
821
|
+
|
413
822
|
end
|
414
823
|
|
415
824
|
end
|
416
825
|
|
417
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
|
+
|
418
835
|
class LocalDatum < Datum
|
419
836
|
|
420
837
|
def _wkt_typename # :nodoc:
|
@@ -427,15 +844,25 @@ module RGeo
|
|
427
844
|
|
428
845
|
class << self
|
429
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
|
+
|
430
852
|
def create(name_, datum_type_, *optional_)
|
431
853
|
new(name_, datum_type_, *optional_)
|
432
854
|
end
|
433
855
|
|
856
|
+
|
434
857
|
end
|
435
858
|
|
436
859
|
end
|
437
860
|
|
438
861
|
|
862
|
+
# == OGC spec description
|
863
|
+
#
|
864
|
+
# Procedure used to measure positions on the surface of the Earth.
|
865
|
+
|
439
866
|
class HorizontalDatum < Datum
|
440
867
|
|
441
868
|
def initialize(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_) # :nodoc:
|
@@ -444,9 +871,16 @@ module RGeo
|
|
444
871
|
@wgs84_parameters = wgs84_parameters_
|
445
872
|
end
|
446
873
|
|
874
|
+
|
875
|
+
# Returns the Ellipsoid.
|
447
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.
|
448
881
|
attr_reader :wgs84_parameters
|
449
882
|
|
883
|
+
|
450
884
|
def _wkt_typename # :nodoc:
|
451
885
|
"DATUM"
|
452
886
|
end
|
@@ -457,17 +891,29 @@ module RGeo
|
|
457
891
|
array_
|
458
892
|
end
|
459
893
|
|
894
|
+
|
460
895
|
class << self
|
461
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
|
+
|
462
903
|
def create(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
|
463
904
|
new(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
|
464
905
|
end
|
465
906
|
|
907
|
+
|
466
908
|
end
|
467
909
|
|
468
910
|
end
|
469
911
|
|
470
912
|
|
913
|
+
# == OGC spec description
|
914
|
+
#
|
915
|
+
# A projection from geographic coordinates to projected coordinates.
|
916
|
+
|
471
917
|
class Projection < Info
|
472
918
|
|
473
919
|
def initialize(name_, class_name_, parameters_, *optional_) # :nodoc:
|
@@ -476,20 +922,33 @@ module RGeo
|
|
476
922
|
@parameters = parameters_ ? parameters_.dup : []
|
477
923
|
end
|
478
924
|
|
925
|
+
|
926
|
+
# Gets the projection classification name
|
927
|
+
# (e.g. "Transverse_Mercator").
|
479
928
|
attr_reader :class_name
|
480
929
|
|
930
|
+
|
931
|
+
# Gets number of parameters of the projection.
|
932
|
+
|
481
933
|
def num_parameters
|
482
934
|
@parameters.size
|
483
935
|
end
|
484
936
|
|
937
|
+
|
938
|
+
# Gets an inexed parameter of the projection.
|
939
|
+
|
485
940
|
def get_parameter(index_)
|
486
941
|
@parameters[index_]
|
487
942
|
end
|
488
943
|
|
944
|
+
|
945
|
+
# Iterates over the parameters of the projection.
|
946
|
+
|
489
947
|
def each_parameter(&block_)
|
490
948
|
@parameters.each(&block_)
|
491
949
|
end
|
492
950
|
|
951
|
+
|
493
952
|
def _wkt_typename # :nodoc:
|
494
953
|
"PROJECTION"
|
495
954
|
end
|
@@ -498,17 +957,53 @@ module RGeo
|
|
498
957
|
[]
|
499
958
|
end
|
500
959
|
|
960
|
+
|
501
961
|
class << self
|
502
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
|
+
|
503
968
|
def create(name_, class_name_, parameters_, *optional_)
|
504
969
|
new(name_, class_name_, parameters_, *optional_)
|
505
970
|
end
|
506
971
|
|
972
|
+
|
507
973
|
end
|
508
974
|
|
509
975
|
end
|
510
976
|
|
511
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
|
+
|
512
1007
|
class CoordinateSystem < Info
|
513
1008
|
|
514
1009
|
def initialize(name_, dimension_, *optional_) # :nodoc:
|
@@ -516,11 +1011,38 @@ module RGeo
|
|
516
1011
|
@dimension = dimension_.to_i
|
517
1012
|
end
|
518
1013
|
|
1014
|
+
|
1015
|
+
# Dimension of the coordinate system
|
519
1016
|
attr_reader :dimension
|
520
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
|
+
|
521
1035
|
end
|
522
1036
|
|
523
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
|
+
|
524
1046
|
class CompoundCoordinateSystem < CoordinateSystem
|
525
1047
|
|
526
1048
|
def initialize(name_, head_, tail_, *optional_) # :nodoc:
|
@@ -529,19 +1051,30 @@ module RGeo
|
|
529
1051
|
@tail = tail_
|
530
1052
|
end
|
531
1053
|
|
1054
|
+
|
1055
|
+
# Gets first sub-coordinate system.
|
532
1056
|
attr_reader :head
|
1057
|
+
|
1058
|
+
# Gets second sub-coordinate system.
|
533
1059
|
attr_reader :tail
|
534
1060
|
|
1061
|
+
|
1062
|
+
# Implements CoordinateSystem#get_axis
|
1063
|
+
|
535
1064
|
def get_axis(index_)
|
536
1065
|
hd_ = @head.dimension
|
537
1066
|
index_ < hd_ ? @head.get_axis(index_) : @tail.get_axis(index_ - hd_)
|
538
1067
|
end
|
539
1068
|
|
1069
|
+
|
1070
|
+
# Implements CoordinateSystem#get_units
|
1071
|
+
|
540
1072
|
def get_units(index_)
|
541
1073
|
hd_ = @head.dimension
|
542
1074
|
index_ < hd_ ? @head.get_units(index_) : @tail.get_units(index_ - hd_)
|
543
1075
|
end
|
544
1076
|
|
1077
|
+
|
545
1078
|
def _wkt_typename # :nodoc:
|
546
1079
|
"COMPD_CS"
|
547
1080
|
end
|
@@ -550,17 +1083,44 @@ module RGeo
|
|
550
1083
|
[@head._to_wkt(open_, close_), @tail._to_wkt(open_, close_)]
|
551
1084
|
end
|
552
1085
|
|
1086
|
+
|
553
1087
|
class << self
|
554
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
|
+
|
555
1094
|
def create(name_, head_, tail_, *optional_)
|
556
1095
|
new(name_, head_, tail_, *optional_)
|
557
1096
|
end
|
558
1097
|
|
1098
|
+
|
559
1099
|
end
|
560
1100
|
|
1101
|
+
|
561
1102
|
end
|
562
1103
|
|
563
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
|
+
|
564
1124
|
class LocalCoordinateSystem < CoordinateSystem
|
565
1125
|
|
566
1126
|
def initialize(name_, local_datum_, unit_, axes_, *optional_) # :nodoc:
|
@@ -570,16 +1130,25 @@ module RGeo
|
|
570
1130
|
@axes = axes_.dup
|
571
1131
|
end
|
572
1132
|
|
1133
|
+
|
1134
|
+
# Gets the local datum.
|
573
1135
|
attr_reader :local_datum
|
574
1136
|
|
1137
|
+
|
1138
|
+
# Implements CoordinateSystem#get_axis
|
1139
|
+
|
575
1140
|
def get_axis(index_)
|
576
1141
|
@axes[index_]
|
577
1142
|
end
|
578
1143
|
|
1144
|
+
|
1145
|
+
# Implements CoordinateSystem#get_units
|
1146
|
+
|
579
1147
|
def get_units(index_)
|
580
1148
|
@unit
|
581
1149
|
end
|
582
1150
|
|
1151
|
+
|
583
1152
|
def _wkt_typename # :nodoc:
|
584
1153
|
"LOCAL_CS"
|
585
1154
|
end
|
@@ -588,17 +1157,34 @@ module RGeo
|
|
588
1157
|
[@local_datum._to_wkt(open_, close_), @unit._to_wkt(open_, close_)] + @axes.map{ |ax_| ax_._to_wkt(open_, close_) }
|
589
1158
|
end
|
590
1159
|
|
1160
|
+
|
591
1161
|
class << self
|
592
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
|
+
|
593
1169
|
def create(name_, local_datum_, unit_, axes_, *optional_)
|
594
1170
|
new(name_, local_datum_, unit_, axes_, *optional_)
|
595
1171
|
end
|
596
1172
|
|
1173
|
+
|
597
1174
|
end
|
598
1175
|
|
599
1176
|
end
|
600
1177
|
|
601
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
|
+
|
602
1188
|
class GeocentricCoordinateSystem < CoordinateSystem
|
603
1189
|
|
604
1190
|
def initialize(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_) # :nodoc:
|
@@ -611,18 +1197,34 @@ module RGeo
|
|
611
1197
|
@axis2 = axis2_
|
612
1198
|
end
|
613
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.
|
614
1205
|
attr_reader :horizontal_datum
|
1206
|
+
|
1207
|
+
# Returns the PrimeMeridian.
|
615
1208
|
attr_reader :prime_meridian
|
1209
|
+
|
1210
|
+
# Gets the units used along all the axes.
|
616
1211
|
attr_reader :linear_unit
|
617
1212
|
|
1213
|
+
|
1214
|
+
# Implements CoordinateSystem#get_units
|
1215
|
+
|
618
1216
|
def get_units(index_)
|
619
1217
|
@linear_unit
|
620
1218
|
end
|
621
1219
|
|
1220
|
+
|
1221
|
+
# Implements CoordinateSystem#get_axis
|
1222
|
+
|
622
1223
|
def get_axis(index_)
|
623
1224
|
[@axis0, @axis1, @axis2][index_]
|
624
1225
|
end
|
625
1226
|
|
1227
|
+
|
626
1228
|
def _wkt_typename # :nodoc:
|
627
1229
|
"GEOCCS"
|
628
1230
|
end
|
@@ -635,17 +1237,32 @@ module RGeo
|
|
635
1237
|
arr_
|
636
1238
|
end
|
637
1239
|
|
1240
|
+
|
638
1241
|
class << self
|
639
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
|
+
|
640
1250
|
def create(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
|
641
1251
|
new(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
|
642
1252
|
end
|
643
1253
|
|
1254
|
+
|
644
1255
|
end
|
645
1256
|
|
1257
|
+
|
646
1258
|
end
|
647
1259
|
|
648
1260
|
|
1261
|
+
# == OGC spec description
|
1262
|
+
#
|
1263
|
+
# A one-dimensional coordinate system suitable for vertical
|
1264
|
+
# measurements.
|
1265
|
+
|
649
1266
|
class VerticalCoordinateSystem < CoordinateSystem
|
650
1267
|
|
651
1268
|
def initialize(name_, vertical_datum_, vertical_unit_, axis_, *optional_) # :nodoc:
|
@@ -655,17 +1272,29 @@ module RGeo
|
|
655
1272
|
@axis = axis_
|
656
1273
|
end
|
657
1274
|
|
1275
|
+
|
1276
|
+
# Gets the vertical datum, which indicates the measurement method.
|
658
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.
|
659
1281
|
attr_reader :vertical_unit
|
660
1282
|
|
1283
|
+
|
1284
|
+
# Implements CoordinateSystem#get_units
|
1285
|
+
|
661
1286
|
def get_units(index_)
|
662
1287
|
@vertical_unit
|
663
1288
|
end
|
664
1289
|
|
1290
|
+
|
1291
|
+
# Implements CoordinateSystem#get_axis
|
1292
|
+
|
665
1293
|
def get_axis(index_)
|
666
1294
|
@axis
|
667
1295
|
end
|
668
1296
|
|
1297
|
+
|
669
1298
|
def _wkt_typename # :nodoc:
|
670
1299
|
"VERT_CS"
|
671
1300
|
end
|
@@ -676,17 +1305,36 @@ module RGeo
|
|
676
1305
|
arr_
|
677
1306
|
end
|
678
1307
|
|
1308
|
+
|
679
1309
|
class << self
|
680
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
|
+
|
681
1317
|
def create(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
|
682
1318
|
new(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
|
683
1319
|
end
|
684
1320
|
|
1321
|
+
|
685
1322
|
end
|
686
1323
|
|
1324
|
+
|
687
1325
|
end
|
688
1326
|
|
689
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
|
+
|
690
1338
|
class HorizontalCoordinateSystem < CoordinateSystem
|
691
1339
|
|
692
1340
|
def initialize(name_, horizontal_datum_, *optional_) # :nodoc:
|
@@ -694,11 +1342,22 @@ module RGeo
|
|
694
1342
|
@horizontal_datum = horizontal_datum_
|
695
1343
|
end
|
696
1344
|
|
1345
|
+
|
1346
|
+
# Returns the HorizontalDatum.
|
697
1347
|
attr_reader :horizontal_datum
|
698
1348
|
|
1349
|
+
|
699
1350
|
end
|
700
1351
|
|
701
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
|
+
|
702
1361
|
class GeographicCoordinateSystem < HorizontalCoordinateSystem
|
703
1362
|
|
704
1363
|
def initialize(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_) # :nodoc:
|
@@ -709,25 +1368,47 @@ module RGeo
|
|
709
1368
|
@axis1 = axis1_
|
710
1369
|
end
|
711
1370
|
|
1371
|
+
|
1372
|
+
# Returns the PrimeMeridian.
|
712
1373
|
attr_reader :prime_meridian
|
1374
|
+
|
1375
|
+
# Returns the AngularUnit. The angular unit must be the same as
|
1376
|
+
# the CS_CoordinateSystem units.
|
713
1377
|
attr_reader :angular_unit
|
714
1378
|
|
1379
|
+
|
1380
|
+
# Implements CoordinateSystem#get_units
|
1381
|
+
|
715
1382
|
def get_units(index_)
|
716
1383
|
@angular_unit
|
717
1384
|
end
|
718
1385
|
|
1386
|
+
|
1387
|
+
# Implements CoordinateSystem#get_axis
|
1388
|
+
|
719
1389
|
def get_axis(index_)
|
720
1390
|
index_ == 1 ? @axis1 : @axis0
|
721
1391
|
end
|
722
1392
|
|
1393
|
+
|
1394
|
+
# Gets the number of available conversions to WGS84 coordinates.
|
1395
|
+
|
723
1396
|
def num_conversion_to_wgs84
|
724
1397
|
@horizontal_datum.wgs84_parameters ? 1 : 0
|
725
1398
|
end
|
726
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
|
+
|
727
1407
|
def get_wgs84_conversion_info(index_)
|
728
1408
|
@horizontal_datum.wgs84_parameters
|
729
1409
|
end
|
730
1410
|
|
1411
|
+
|
731
1412
|
def _wkt_typename # :nodoc:
|
732
1413
|
"GEOGCS"
|
733
1414
|
end
|
@@ -739,17 +1420,31 @@ module RGeo
|
|
739
1420
|
arr_
|
740
1421
|
end
|
741
1422
|
|
1423
|
+
|
742
1424
|
class << self
|
743
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
|
+
|
744
1433
|
def create(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
|
745
1434
|
new(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
|
746
1435
|
end
|
747
1436
|
|
1437
|
+
|
748
1438
|
end
|
749
1439
|
|
1440
|
+
|
750
1441
|
end
|
751
1442
|
|
752
1443
|
|
1444
|
+
# == OGC spec description
|
1445
|
+
#
|
1446
|
+
# A 2D cartographic coordinate system.
|
1447
|
+
|
753
1448
|
class ProjectedCoordinateSystem < HorizontalCoordinateSystem
|
754
1449
|
|
755
1450
|
def initialize(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_) # :nodoc:
|
@@ -761,18 +1456,32 @@ module RGeo
|
|
761
1456
|
@axis1 = axis1_
|
762
1457
|
end
|
763
1458
|
|
1459
|
+
|
1460
|
+
# Returns the GeographicCoordinateSystem.
|
764
1461
|
attr_reader :geographic_coordinate_system
|
1462
|
+
|
1463
|
+
# Gets the projection.
|
765
1464
|
attr_reader :projection
|
1465
|
+
|
1466
|
+
# Returns the LinearUnits. The linear unit must be the same as
|
1467
|
+
# the CS_CoordinateSystem units.
|
766
1468
|
attr_reader :linear_unit
|
767
1469
|
|
1470
|
+
|
1471
|
+
# Implements CoordinateSystem#get_units
|
1472
|
+
|
768
1473
|
def get_units(index_)
|
769
1474
|
@linear_unit
|
770
1475
|
end
|
771
1476
|
|
1477
|
+
|
1478
|
+
# Implements CoordinateSystem#get_axis
|
1479
|
+
|
772
1480
|
def get_axis(index_)
|
773
1481
|
index_ == 1 ? @axis1 : @axis0
|
774
1482
|
end
|
775
1483
|
|
1484
|
+
|
776
1485
|
def _wkt_typename # :nodoc:
|
777
1486
|
"PROJCS"
|
778
1487
|
end
|
@@ -786,14 +1495,24 @@ module RGeo
|
|
786
1495
|
arr_
|
787
1496
|
end
|
788
1497
|
|
1498
|
+
|
789
1499
|
class << self
|
790
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
|
+
|
791
1508
|
def create(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
|
792
1509
|
new(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
|
793
1510
|
end
|
794
1511
|
|
1512
|
+
|
795
1513
|
end
|
796
1514
|
|
1515
|
+
|
797
1516
|
end
|
798
1517
|
|
799
1518
|
|