proj4rb 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/projrb.c +0 -2
- data/lib/proj4.rb +417 -410
- data/test/test_constants.rb +12 -14
- data/test/test_create_projection.rb +57 -58
- data/test/test_datums.rb +38 -37
- data/test/test_ellipsoids.rb +38 -37
- data/test/test_errors.rb +50 -54
- data/test/test_init_projection.rb +94 -93
- data/test/test_prime_meridians.rb +37 -36
- data/test/test_projection_type.rb +36 -35
- data/test/test_simple_projection.rb +50 -49
- data/test/test_suite.rb +14 -0
- data/test/test_transform.rb +99 -98
- data/test/test_units.rb +38 -37
- metadata +6 -4
data/lib/proj4.rb
CHANGED
@@ -1,466 +1,473 @@
|
|
1
|
+
# encoding: UTF-8
|
1
2
|
|
2
3
|
if File.exists?(File.dirname(__FILE__ + '/../data'))
|
3
|
-
|
4
|
+
ENV['PROJ_LIB'] = File.dirname(__FILE__) + '/../data'
|
4
5
|
end
|
5
6
|
|
6
|
-
|
7
|
+
# Load the C-based binding.
|
8
|
+
begin
|
9
|
+
RUBY_VERSION =~ /(\d+.\d+)/
|
10
|
+
require "#{$1}/proj4_ruby"
|
11
|
+
rescue LoadError
|
12
|
+
require "proj4_ruby"
|
13
|
+
end
|
7
14
|
|
8
15
|
# Ruby bindings for the Proj.4 cartographic projection library (http://trac.osgeo.org/proj/).
|
9
16
|
module Proj4
|
10
17
|
|
11
|
-
|
12
|
-
|
18
|
+
# Base class for all Proj.4 exceptions. Subclasses with the name <errorname>Error are available for each exception.
|
19
|
+
class Error < StandardError
|
20
|
+
|
21
|
+
# List of all Proj.4 errors.
|
22
|
+
#--
|
23
|
+
# (This list is created from the one in pj_strerrno.c in the Proj.4 distribution.)
|
24
|
+
#++
|
25
|
+
ERRORS = %w{Unknown NoArgsInInitList NoOptionsInInitFile NoColonInInitString ProjectionNotNamed UnknownProjectionId EffectiveEccentricityEq1 UnknownUnitConversionId InvalidBooleanParamArgument UnknownEllipticalParameterName ReciprocalFlatteningIsZero RadiusReferenceLatitudeGt90 SquaredEccentricityLessThanZero MajorAxisOrRadiusIsZeroOrNotGiven LatitudeOrLongitudeExceededLimits InvalidXOrY ImproperlyFormedDMSValue NonConvergentInverseMeridinalDist NonConvergentInversePhi2 AcosOrAsinArgTooBig ToleranceCondition ConicLat1EqMinusLat2 Lat1GreaterThan90 Lat1IsZero LatTsGreater90 NoDistanceBetweenControlPoints ProjectionNotSelectedToBeRotated WSmallerZeroOrMSmallerZero LsatNotInRange PathNotInRange HSmallerZero KSmallerZero Lat0IsZeroOr90OrAlphaIsZero Lat1EqLat2OrLat1IsZeroOrLat2Is90 EllipticalUsageRequired InvalidUTMZoneNumber ArgsOutOfRangeForTchebyEval NoProjectionToBeRotated FailedToLoadNAD2783CorrectionFile BothNAndMMustBeSpecdAndGreaterZero NSmallerZeroOrNGreaterOneOrNotSpecified Lat1OrLat2NotSpecified AbsoluteLat1EqLat2 Lat0IsHalfPiFromMeanLat UnparseableCoordinateSystemDefinition GeocentricTransformationMissingZOrEllps UnknownPrimeMeridianConversionId}
|
26
|
+
|
27
|
+
# Return list of all errors.
|
28
|
+
#
|
29
|
+
# call-seq: list -> Array
|
30
|
+
#
|
31
|
+
def self.list
|
32
|
+
ERRORS
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return name of error with given number.
|
36
|
+
#
|
37
|
+
# call-seq: error(errnum) -> String
|
38
|
+
#
|
39
|
+
def self.error(errnum)
|
40
|
+
ERRORS[errnum.abs] || 'Unknown'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Raise an error with error number +errnum+.
|
44
|
+
def self.raise_error(errnum)
|
45
|
+
raise eval("#{error(errnum.abs)}Error"), message(-(errnum.abs)), caller[0..-1]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return error number of this error.
|
49
|
+
def errnum
|
50
|
+
self.class.errnum
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
Error.list.each_with_index do |err, index|
|
56
|
+
eval "class #{err}Error < Error;
|
57
|
+
def self.errnum;
|
58
|
+
#{index};
|
59
|
+
end;
|
60
|
+
end"
|
61
|
+
end
|
62
|
+
|
63
|
+
# The Projection class represents a geographical projection.
|
64
|
+
#
|
65
|
+
# = Creating a new projection object
|
66
|
+
#
|
67
|
+
# Projection objects are created through the new method as usual. Depending on the kind of projection, many
|
68
|
+
# different parameters are needed. Please consult the documentation of the Proj.4 C library at http://trac.osgeo.org/proj/
|
69
|
+
# for details.
|
70
|
+
#
|
71
|
+
# There are several ways of specifying the parameters:
|
72
|
+
#
|
73
|
+
# [<b>as a String:</b>] A string with the parameters in '[+]key=value' format concatenated together. This is the format used by the <tt>proj</tt> and <tt>cs2cs</tt> command line tool.
|
74
|
+
#
|
75
|
+
# proj = Projection.new "+proj=utm +zone=21 +units=m"
|
76
|
+
#
|
77
|
+
# [<b>as an Array:</b>] An array with each parameter as a member in the array in '[+]key=value' format.
|
78
|
+
#
|
79
|
+
# proj = Projection.new [ "proj=utm", "zone=21", "units=m" ]
|
80
|
+
#
|
81
|
+
# [<b>as a Hash:</b>] A hash with strings or symbols as keys.
|
82
|
+
#
|
83
|
+
# proj = Projection.new( "proj" => "utm", "zone" => "21", "units" => "m" )
|
84
|
+
# proj = Projection.new( :proj => "utm", :zone => "21", :units => "m" )
|
85
|
+
#
|
86
|
+
# With all variants the plus sign in front of the keys is optional.
|
87
|
+
#
|
88
|
+
# = Using a projection object to project points
|
89
|
+
#
|
90
|
+
# There are two ways a projection can be used: Through the +forward+ and +inverse+ methods (with all their variants)
|
91
|
+
# you can do projection from longitudes and latitudes into the coordinate system used by the projection and back.
|
92
|
+
# These projections are always 2D, i.e. you need and get lon/lat or x/y coordinates.
|
93
|
+
#
|
94
|
+
# The alternative is the +transform+ method (with all its variants) which is used to transform 3D points from one
|
95
|
+
# projection and datum to another. In addition to the x/y coordinates the transform method also reads and returns
|
96
|
+
# a z coordinate.
|
97
|
+
#
|
98
|
+
# = Versions of the projection methods
|
99
|
+
#
|
100
|
+
# All three projection methods (+forward+, +inverse+, and +transform+) work on points. Every method has an in-place
|
101
|
+
# version (with a name ending in !) which changes the given point and a normal version which first creates a copy of
|
102
|
+
# the point object and changes and returns that. All methods use radians when reading or returning points. For
|
103
|
+
# convenience there are also +forwardDeg+ and +inverseDeg+ methods (and in-place versions <tt>forwardDeg!</tt>
|
104
|
+
# and <tt>inverseDeg!</tt>) that will work with degrees.
|
105
|
+
#
|
106
|
+
# = Points
|
107
|
+
#
|
108
|
+
# All projection method project points to other points. You can use objects of the Proj4::Point class for this or
|
109
|
+
# any other object which supports the x, y, z read and write accessor methods. (In fact you don't even need the
|
110
|
+
# z accessor methods, 0 is assumed if they don't exist.)
|
111
|
+
#
|
112
|
+
# Some projection methods act on the given point in-place, other return a copy of the point object. But in any case
|
113
|
+
# all other attributes of the point object are retained.
|
114
|
+
#
|
115
|
+
# = Projection collections
|
116
|
+
#
|
117
|
+
# The methods forward_all, inverse_all, and transform_all (and their in-place versions forward_all!,
|
118
|
+
# inverse_all!, and transform_all! work just like their simple counterparts, but instead of a single
|
119
|
+
# point they convert a collection of points in one go.
|
120
|
+
#
|
121
|
+
# These methods all take an array as an argument or any object responding to the +each+ method (for the in-place versions)
|
122
|
+
# or +each+, +clear+, and <tt><<</tt> methods (for the normal version).
|
123
|
+
#
|
124
|
+
# Some projection methods act on the given collection in-place, i.e. the collection is not touched and all points
|
125
|
+
# in the collection will be projected in-place. The other methods act on a copy of the collection and on copies
|
126
|
+
# of each point in the collection. So you'll get back a brand new copy of the collection with new copies of the
|
127
|
+
# points with the projected coordinates. In any case all other attributes of the collection and points are retained.
|
128
|
+
#
|
129
|
+
class Projection
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def self._parse_init_parameters(args)
|
134
|
+
case args
|
135
|
+
when Array
|
136
|
+
args.collect{ |a| a.sub(/^\+/, '') }
|
137
|
+
when String
|
138
|
+
args.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
|
139
|
+
when Hash
|
140
|
+
array = []
|
141
|
+
args.each_pair{ | key, value | array << (value.nil? ? key.to_s : "#{key}=#{value}") }
|
142
|
+
array
|
143
|
+
when Proj4::Projection
|
144
|
+
args.getDef.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
|
145
|
+
else
|
146
|
+
raise ArgumentError, "Unknown type #{args.class} for projection definition"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
public
|
151
|
+
|
152
|
+
# Get the ID of this projection.
|
153
|
+
#
|
154
|
+
# call-seq: projection -> String
|
155
|
+
#
|
156
|
+
def projection
|
157
|
+
getDef =~ /\+proj=(.+?) / ? $1 : nil
|
158
|
+
end
|
159
|
+
|
160
|
+
# Get the ID of the datum used in this projection.
|
161
|
+
#
|
162
|
+
# call-seq: datum -> String
|
163
|
+
#
|
164
|
+
def datum
|
165
|
+
getDef =~ /\+datum=(.+?) / ? $1 : nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# Get definition of projection in typical inspect format (#<Proj4::Projection +init=... +proj=... ...>).
|
169
|
+
#
|
170
|
+
# call-seq: to_s -> String
|
171
|
+
#
|
172
|
+
def to_s
|
173
|
+
"#<Proj4::Projection#{ getDef }>"
|
174
|
+
end
|
13
175
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
176
|
+
# Forward projection of a point. Returns a copy of the point object with coordinates projected.
|
177
|
+
#
|
178
|
+
# call-seq: forward(point) -> point
|
179
|
+
#
|
180
|
+
def forward(point)
|
181
|
+
forward!(point.dup)
|
182
|
+
end
|
19
183
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
184
|
+
# Convenience function for calculating a forward projection with degrees instead of radians.
|
185
|
+
#
|
186
|
+
# call-seq: forwardDeg(point) -> point
|
187
|
+
#
|
188
|
+
def forwardDeg(point)
|
189
|
+
forwardDeg!(point.dup)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Convenience function for calculating a forward projection with degrees instead of radians.
|
193
|
+
# This version works in-place, i.e. the point objects content is overwritten.
|
194
|
+
#
|
195
|
+
# call-seq: forwardDeg!(point) -> point
|
196
|
+
#
|
197
|
+
def forwardDeg!(point)
|
198
|
+
point.x *= Proj4::DEG_TO_RAD
|
199
|
+
point.y *= Proj4::DEG_TO_RAD
|
200
|
+
forward!(point)
|
201
|
+
end
|
27
202
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
203
|
+
# Project all points in a collection 'in place'.
|
204
|
+
# The +collection+ object must implement the +each+
|
205
|
+
# method for this to work.
|
206
|
+
#
|
207
|
+
# call-seq: forward_all!(collection) -> collection
|
208
|
+
#
|
209
|
+
def forward_all!(collection)
|
210
|
+
collection.each do |point|
|
211
|
+
forward!(point)
|
212
|
+
end
|
213
|
+
collection
|
214
|
+
end
|
35
215
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
216
|
+
# Projects all points in a collection.
|
217
|
+
# The +collection+ object must implement the +each+,
|
218
|
+
# +clear+, and << methods (just like an Array) for this to work.
|
219
|
+
#
|
220
|
+
# call-seq: forward_all(collection) -> collection
|
221
|
+
#
|
222
|
+
def forward_all(collection)
|
223
|
+
newcollection = collection.dup.clear
|
224
|
+
collection.each do |point|
|
225
|
+
newcollection << forward(point)
|
226
|
+
end
|
227
|
+
newcollection
|
228
|
+
end
|
40
229
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
230
|
+
# Inverse projection of a point. Returns a copy of the point object with coordinates projected.
|
231
|
+
#
|
232
|
+
# call-seq: inverse(point) -> point
|
233
|
+
#
|
234
|
+
def inverse(point)
|
235
|
+
inverse!(point.dup)
|
236
|
+
end
|
45
237
|
|
238
|
+
# Convenience function for calculating an inverse projection with the result in degrees instead of radians.
|
239
|
+
#
|
240
|
+
# call-seq: inverseDeg(point) -> point
|
241
|
+
#
|
242
|
+
def inverseDeg(point)
|
243
|
+
inverseDeg!(point.dup)
|
46
244
|
end
|
47
245
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
246
|
+
# Convenience function for calculating an inverse projection with the result in degrees instead of radians.
|
247
|
+
# This version works in-place, i.e. the point objects content is overwritten.
|
248
|
+
#
|
249
|
+
# call-seq: inverseDeg!(point) -> point
|
250
|
+
#
|
251
|
+
def inverseDeg!(point)
|
252
|
+
inverse!(point)
|
253
|
+
point.x *= Proj4::RAD_TO_DEG
|
254
|
+
point.y *= Proj4::RAD_TO_DEG
|
255
|
+
point
|
54
256
|
end
|
55
257
|
|
56
|
-
#
|
258
|
+
# Project all points in a collection 'in place'.
|
259
|
+
# The +collection+ object must implement the +each+
|
260
|
+
# method for this to work.
|
57
261
|
#
|
58
|
-
#
|
262
|
+
# call-seq: inverse_all!(collection) -> collection
|
59
263
|
#
|
60
|
-
|
61
|
-
|
62
|
-
|
264
|
+
def inverse_all!(collection)
|
265
|
+
collection.each do |point|
|
266
|
+
inverse!(point)
|
267
|
+
end
|
268
|
+
collection
|
269
|
+
end
|
270
|
+
|
271
|
+
# Projects all points in a collection.
|
272
|
+
# The +collection+ object must implement the +each+,
|
273
|
+
# +clear+, and << methods (just like an Array) for this to work.
|
63
274
|
#
|
64
|
-
#
|
275
|
+
# call-seq: inverse_all(collection) -> collection
|
65
276
|
#
|
66
|
-
|
277
|
+
def inverse_all(collection)
|
278
|
+
newcollection = collection.dup.clear
|
279
|
+
collection.each do |point|
|
280
|
+
newcollection << inverse(point)
|
281
|
+
end
|
282
|
+
newcollection
|
283
|
+
end
|
284
|
+
|
285
|
+
# Transforms a point from one projection to another.
|
67
286
|
#
|
68
|
-
#
|
287
|
+
# call-seq: transform(destinationProjection, point) -> point
|
69
288
|
#
|
70
|
-
|
289
|
+
def transform(otherProjection, point)
|
290
|
+
transform!(otherProjection, point.dup)
|
291
|
+
end
|
292
|
+
|
293
|
+
# Transforms all points in a collection 'in place' from one projection
|
294
|
+
# to another. The +collection+ object must implement the +each+
|
295
|
+
# method for this to work.
|
71
296
|
#
|
72
|
-
#
|
297
|
+
# call-seq: transform_all!(destinationProjection, collection) -> collection
|
73
298
|
#
|
74
|
-
|
299
|
+
def transform_all!(otherProjection, collection)
|
300
|
+
collection.each do |point|
|
301
|
+
transform!(otherProjection, point)
|
302
|
+
end
|
303
|
+
collection
|
304
|
+
end
|
305
|
+
|
306
|
+
# Transforms all points in a collection from one projection to
|
307
|
+
# another. The +collection+ object must implement the +each+,
|
308
|
+
# +clear+, and << methods (just like an Array) for this to work.
|
309
|
+
#
|
310
|
+
# call-seq: transform_all(destinationProjection, collection) -> collection
|
75
311
|
#
|
76
|
-
|
77
|
-
|
312
|
+
def transform_all(otherProjection, collection)
|
313
|
+
newcollection = collection.dup.clear
|
314
|
+
collection.each do |point|
|
315
|
+
newcollection << transform(otherProjection, point)
|
316
|
+
end
|
317
|
+
newcollection
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
# This class represents a point in either lon/lat or projected x/y coordinates.
|
323
|
+
class Point
|
324
|
+
|
325
|
+
# X coordinate or longitude
|
326
|
+
attr_accessor :x
|
327
|
+
|
328
|
+
# Y coordinate or latitude
|
329
|
+
attr_accessor :y
|
330
|
+
|
331
|
+
# Z coordinate (height)
|
332
|
+
attr_accessor :z
|
333
|
+
|
334
|
+
# Create new Proj4::Point object from coordinates.
|
335
|
+
def initialize(x, y, z=0)
|
336
|
+
@x = x
|
337
|
+
@y = y
|
338
|
+
@z = z
|
339
|
+
end
|
340
|
+
|
341
|
+
# Get longitude/x coordinate.
|
342
|
+
def lon
|
343
|
+
x
|
344
|
+
end
|
345
|
+
|
346
|
+
# Get latitude/y coordinate.
|
347
|
+
def lat
|
348
|
+
y
|
349
|
+
end
|
350
|
+
|
351
|
+
# Set longitude/x coordinate.
|
352
|
+
def lon=(lon)
|
353
|
+
@x = lon
|
354
|
+
end
|
355
|
+
|
356
|
+
# Set latitude/y coordinate.
|
357
|
+
def lat=(lat)
|
358
|
+
@y = lat
|
359
|
+
end
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
# Abstract base class for several types of definitions: Proj4::Datum, Proj4::Ellipsoid, Proj4::PrimeMeridian, Proj4::ProjectionType, Proj4::Unit.
|
364
|
+
#
|
365
|
+
# Note that these classes only work if the version of the Proj.4 C library used is at least 449.
|
366
|
+
class Def
|
367
|
+
|
368
|
+
# Initialize function raises error. Definitions are always defined by the underlying Proj.4 library, you can't create them yourself.
|
369
|
+
def initialize # :nodoc:
|
370
|
+
raise TypeError, "You can't created objects of this type yourself."
|
371
|
+
end
|
372
|
+
|
373
|
+
# Get the definition with given id.
|
374
|
+
def self.get(id)
|
375
|
+
self.list.select{ |u| u.id == id }.first
|
376
|
+
end
|
377
|
+
|
378
|
+
# Compares definitions by comparing ids.
|
78
379
|
#
|
79
|
-
#
|
380
|
+
# call-seq: one == other -> true or false
|
80
381
|
#
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# you can do projection from longitudes and latitudes into the coordinate system used by the projection and back.
|
85
|
-
# These projections are always 2D, i.e. you need and get lon/lat or x/y coordinates.
|
86
|
-
#
|
87
|
-
# The alternative is the +transform+ method (with all its variants) which is used to transform 3D points from one
|
88
|
-
# projection and datum to another. In addition to the x/y coordinates the transform method also reads and returns
|
89
|
-
# a z coordinate.
|
90
|
-
#
|
91
|
-
# = Versions of the projection methods
|
92
|
-
#
|
93
|
-
# All three projection methods (+forward+, +inverse+, and +transform+) work on points. Every method has an in-place
|
94
|
-
# version (with a name ending in !) which changes the given point and a normal version which first creates a copy of
|
95
|
-
# the point object and changes and returns that. All methods use radians when reading or returning points. For
|
96
|
-
# convenience there are also +forwardDeg+ and +inverseDeg+ methods (and in-place versions <tt>forwardDeg!</tt>
|
97
|
-
# and <tt>inverseDeg!</tt>) that will work with degrees.
|
98
|
-
#
|
99
|
-
# = Points
|
100
|
-
#
|
101
|
-
# All projection method project points to other points. You can use objects of the Proj4::Point class for this or
|
102
|
-
# any other object which supports the x, y, z read and write accessor methods. (In fact you don't even need the
|
103
|
-
# z accessor methods, 0 is assumed if they don't exist.)
|
104
|
-
#
|
105
|
-
# Some projection methods act on the given point in-place, other return a copy of the point object. But in any case
|
106
|
-
# all other attributes of the point object are retained.
|
107
|
-
#
|
108
|
-
# = Projection collections
|
109
|
-
#
|
110
|
-
# The methods forward_all, inverse_all, and transform_all (and their in-place versions forward_all!,
|
111
|
-
# inverse_all!, and transform_all! work just like their simple counterparts, but instead of a single
|
112
|
-
# point they convert a collection of points in one go.
|
113
|
-
#
|
114
|
-
# These methods all take an array as an argument or any object responding to the +each+ method (for the in-place versions)
|
115
|
-
# or +each+, +clear+, and <tt><<</tt> methods (for the normal version).
|
116
|
-
#
|
117
|
-
# Some projection methods act on the given collection in-place, i.e. the collection is not touched and all points
|
118
|
-
# in the collection will be projected in-place. The other methods act on a copy of the collection and on copies
|
119
|
-
# of each point in the collection. So you'll get back a brand new copy of the collection with new copies of the
|
120
|
-
# points with the projected coordinates. In any case all other attributes of the collection and points are retained.
|
121
|
-
#
|
122
|
-
class Projection
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def self._parse_init_parameters(args)
|
127
|
-
case args
|
128
|
-
when Array
|
129
|
-
args.collect{ |a| a.sub(/^\+/, '') }
|
130
|
-
when String
|
131
|
-
args.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
|
132
|
-
when Hash
|
133
|
-
array = []
|
134
|
-
args.each_pair{ | key, value | array << (value.nil? ? key.to_s : "#{key}=#{value}") }
|
135
|
-
array
|
136
|
-
when Proj4::Projection
|
137
|
-
args.getDef.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
|
138
|
-
else
|
139
|
-
raise ArgumentError, "Unknown type #{args.class} for projection definition"
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
public
|
144
|
-
|
145
|
-
# Get the ID of this projection.
|
146
|
-
#
|
147
|
-
# call-seq: projection -> String
|
148
|
-
#
|
149
|
-
def projection
|
150
|
-
getDef =~ /\+proj=(.+?) / ? $1 : nil
|
151
|
-
end
|
152
|
-
|
153
|
-
# Get the ID of the datum used in this projection.
|
154
|
-
#
|
155
|
-
# call-seq: datum -> String
|
156
|
-
#
|
157
|
-
def datum
|
158
|
-
getDef =~ /\+datum=(.+?) / ? $1 : nil
|
159
|
-
end
|
160
|
-
|
161
|
-
# Get definition of projection in typical inspect format (#<Proj4::Projection +init=... +proj=... ...>).
|
162
|
-
#
|
163
|
-
# call-seq: to_s -> String
|
164
|
-
#
|
165
|
-
def to_s
|
166
|
-
"#<Proj4::Projection#{ getDef }>"
|
167
|
-
end
|
168
|
-
|
169
|
-
# Forward projection of a point. Returns a copy of the point object with coordinates projected.
|
170
|
-
#
|
171
|
-
# call-seq: forward(point) -> point
|
172
|
-
#
|
173
|
-
def forward(point)
|
174
|
-
forward!(point.dup)
|
175
|
-
end
|
176
|
-
|
177
|
-
# Convenience function for calculating a forward projection with degrees instead of radians.
|
178
|
-
#
|
179
|
-
# call-seq: forwardDeg(point) -> point
|
180
|
-
#
|
181
|
-
def forwardDeg(point)
|
182
|
-
forwardDeg!(point.dup)
|
183
|
-
end
|
184
|
-
|
185
|
-
# Convenience function for calculating a forward projection with degrees instead of radians.
|
186
|
-
# This version works in-place, i.e. the point objects content is overwritten.
|
187
|
-
#
|
188
|
-
# call-seq: forwardDeg!(point) -> point
|
189
|
-
#
|
190
|
-
def forwardDeg!(point)
|
191
|
-
point.x *= Proj4::DEG_TO_RAD
|
192
|
-
point.y *= Proj4::DEG_TO_RAD
|
193
|
-
forward!(point)
|
194
|
-
end
|
195
|
-
|
196
|
-
# Project all points in a collection 'in place'.
|
197
|
-
# The +collection+ object must implement the +each+
|
198
|
-
# method for this to work.
|
199
|
-
#
|
200
|
-
# call-seq: forward_all!(collection) -> collection
|
201
|
-
#
|
202
|
-
def forward_all!(collection)
|
203
|
-
collection.each do |point|
|
204
|
-
forward!(point)
|
205
|
-
end
|
206
|
-
collection
|
207
|
-
end
|
208
|
-
|
209
|
-
# Projects all points in a collection.
|
210
|
-
# The +collection+ object must implement the +each+,
|
211
|
-
# +clear+, and << methods (just like an Array) for this to work.
|
212
|
-
#
|
213
|
-
# call-seq: forward_all(collection) -> collection
|
214
|
-
#
|
215
|
-
def forward_all(collection)
|
216
|
-
newcollection = collection.dup.clear
|
217
|
-
collection.each do |point|
|
218
|
-
newcollection << forward(point)
|
219
|
-
end
|
220
|
-
newcollection
|
221
|
-
end
|
222
|
-
|
223
|
-
# Inverse projection of a point. Returns a copy of the point object with coordinates projected.
|
224
|
-
#
|
225
|
-
# call-seq: inverse(point) -> point
|
226
|
-
#
|
227
|
-
def inverse(point)
|
228
|
-
inverse!(point.dup)
|
229
|
-
end
|
230
|
-
|
231
|
-
# Convenience function for calculating an inverse projection with the result in degrees instead of radians.
|
232
|
-
#
|
233
|
-
# call-seq: inverseDeg(point) -> point
|
234
|
-
#
|
235
|
-
def inverseDeg(point)
|
236
|
-
inverseDeg!(point.dup)
|
237
|
-
end
|
238
|
-
|
239
|
-
# Convenience function for calculating an inverse projection with the result in degrees instead of radians.
|
240
|
-
# This version works in-place, i.e. the point objects content is overwritten.
|
241
|
-
#
|
242
|
-
# call-seq: inverseDeg!(point) -> point
|
243
|
-
#
|
244
|
-
def inverseDeg!(point)
|
245
|
-
inverse!(point)
|
246
|
-
point.x *= Proj4::RAD_TO_DEG
|
247
|
-
point.y *= Proj4::RAD_TO_DEG
|
248
|
-
point
|
249
|
-
end
|
250
|
-
|
251
|
-
# Project all points in a collection 'in place'.
|
252
|
-
# The +collection+ object must implement the +each+
|
253
|
-
# method for this to work.
|
254
|
-
#
|
255
|
-
# call-seq: inverse_all!(collection) -> collection
|
256
|
-
#
|
257
|
-
def inverse_all!(collection)
|
258
|
-
collection.each do |point|
|
259
|
-
inverse!(point)
|
260
|
-
end
|
261
|
-
collection
|
262
|
-
end
|
263
|
-
|
264
|
-
# Projects all points in a collection.
|
265
|
-
# The +collection+ object must implement the +each+,
|
266
|
-
# +clear+, and << methods (just like an Array) for this to work.
|
267
|
-
#
|
268
|
-
# call-seq: inverse_all(collection) -> collection
|
269
|
-
#
|
270
|
-
def inverse_all(collection)
|
271
|
-
newcollection = collection.dup.clear
|
272
|
-
collection.each do |point|
|
273
|
-
newcollection << inverse(point)
|
274
|
-
end
|
275
|
-
newcollection
|
276
|
-
end
|
277
|
-
|
278
|
-
# Transforms a point from one projection to another.
|
279
|
-
#
|
280
|
-
# call-seq: transform(destinationProjection, point) -> point
|
281
|
-
#
|
282
|
-
def transform(otherProjection, point)
|
283
|
-
transform!(otherProjection, point.dup)
|
284
|
-
end
|
285
|
-
|
286
|
-
# Transforms all points in a collection 'in place' from one projection
|
287
|
-
# to another. The +collection+ object must implement the +each+
|
288
|
-
# method for this to work.
|
289
|
-
#
|
290
|
-
# call-seq: transform_all!(destinationProjection, collection) -> collection
|
291
|
-
#
|
292
|
-
def transform_all!(otherProjection, collection)
|
293
|
-
collection.each do |point|
|
294
|
-
transform!(otherProjection, point)
|
295
|
-
end
|
296
|
-
collection
|
297
|
-
end
|
298
|
-
|
299
|
-
# Transforms all points in a collection from one projection to
|
300
|
-
# another. The +collection+ object must implement the +each+,
|
301
|
-
# +clear+, and << methods (just like an Array) for this to work.
|
302
|
-
#
|
303
|
-
# call-seq: transform_all(destinationProjection, collection) -> collection
|
304
|
-
#
|
305
|
-
def transform_all(otherProjection, collection)
|
306
|
-
newcollection = collection.dup.clear
|
307
|
-
collection.each do |point|
|
308
|
-
newcollection << transform(otherProjection, point)
|
309
|
-
end
|
310
|
-
newcollection
|
311
|
-
end
|
312
|
-
|
313
|
-
end
|
314
|
-
|
315
|
-
# This class represents a point in either lon/lat or projected x/y coordinates.
|
316
|
-
class Point
|
317
|
-
|
318
|
-
# X coordinate or longitude
|
319
|
-
attr_accessor :x
|
320
|
-
|
321
|
-
# Y coordinate or latitude
|
322
|
-
attr_accessor :y
|
323
|
-
|
324
|
-
# Z coordinate (height)
|
325
|
-
attr_accessor :z
|
326
|
-
|
327
|
-
# Create new Proj4::Point object from coordinates.
|
328
|
-
def initialize(x, y, z=0)
|
329
|
-
@x = x
|
330
|
-
@y = y
|
331
|
-
@z = z
|
332
|
-
end
|
333
|
-
|
334
|
-
# Get longitude/x coordinate.
|
335
|
-
def lon
|
336
|
-
x
|
337
|
-
end
|
338
|
-
|
339
|
-
# Get latitude/y coordinate.
|
340
|
-
def lat
|
341
|
-
y
|
342
|
-
end
|
343
|
-
|
344
|
-
# Set longitude/x coordinate.
|
345
|
-
def lon=(lon)
|
346
|
-
@x = lon
|
347
|
-
end
|
348
|
-
|
349
|
-
# Set latitude/y coordinate.
|
350
|
-
def lat=(lat)
|
351
|
-
@y = lat
|
352
|
-
end
|
353
|
-
|
354
|
-
end
|
355
|
-
|
356
|
-
# Abstract base class for several types of definitions: Proj4::Datum, Proj4::Ellipsoid, Proj4::PrimeMeridian, Proj4::ProjectionType, Proj4::Unit.
|
357
|
-
#
|
358
|
-
# Note that these classes only work if the version of the Proj.4 C library used is at least 449.
|
359
|
-
class Def
|
360
|
-
|
361
|
-
# Initialize function raises error. Definitions are always defined by the underlying Proj.4 library, you can't create them yourself.
|
362
|
-
def initialize # :nodoc:
|
363
|
-
raise TypeError, "You can't created objects of this type yourself."
|
364
|
-
end
|
365
|
-
|
366
|
-
# Get the definition with given id.
|
367
|
-
def self.get(id)
|
368
|
-
self.list.select{ |u| u.id == id }.first
|
369
|
-
end
|
370
|
-
|
371
|
-
# Compares definitions by comparing ids.
|
372
|
-
#
|
373
|
-
# call-seq: one == other -> true or false
|
374
|
-
#
|
375
|
-
def ==(other)
|
376
|
-
self.id == other.id
|
377
|
-
end
|
378
|
-
|
379
|
-
# Compares definitions by comparing ids.
|
380
|
-
#
|
381
|
-
# call-seq: one <=> other -> -1, 0, 1
|
382
|
-
#
|
383
|
-
def <=>(other)
|
384
|
-
self.id <=> other.id
|
385
|
-
end
|
382
|
+
def ==(other)
|
383
|
+
self.id == other.id
|
384
|
+
end
|
386
385
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
386
|
+
# Compares definitions by comparing ids.
|
387
|
+
#
|
388
|
+
# call-seq: one <=> other -> -1, 0, 1
|
389
|
+
#
|
390
|
+
def <=>(other)
|
391
|
+
self.id <=> other.id
|
392
|
+
end
|
394
393
|
|
394
|
+
# Stringify definition. Returns ID of this definition.
|
395
|
+
#
|
396
|
+
# call-seq: to_s -> String
|
397
|
+
#
|
398
|
+
def to_s
|
399
|
+
id
|
395
400
|
end
|
396
401
|
|
397
|
-
|
402
|
+
end
|
398
403
|
|
399
|
-
|
400
|
-
#
|
401
|
-
# call-seq: inspect -> String
|
402
|
-
#
|
403
|
-
def inspect
|
404
|
-
"#<Proj4::Datum id=\"#{id}\", ellipse_id=\"#{ellipse_id}\", defn=\"#{defn}\", comments=\"#{comments}\">"
|
405
|
-
end
|
404
|
+
class Datum < Def
|
406
405
|
|
406
|
+
# Returns datum definition as string in format '#<Proj4::Datum id="...", ellipse_id="...", defn="...", comments="...">'.
|
407
|
+
#
|
408
|
+
# call-seq: inspect -> String
|
409
|
+
#
|
410
|
+
def inspect
|
411
|
+
"#<Proj4::Datum id=\"#{id}\", ellipse_id=\"#{ellipse_id}\", defn=\"#{defn}\", comments=\"#{comments}\">"
|
407
412
|
end
|
408
413
|
|
409
|
-
|
414
|
+
end
|
410
415
|
|
411
|
-
|
412
|
-
#
|
413
|
-
# call-seq: inspect -> String
|
414
|
-
#
|
415
|
-
def inspect
|
416
|
-
"#<Proj4::Ellipsoid id=\"#{id}\", major=\"#{major}\", ell=\"#{ell}\", name=\"#{name}\">"
|
417
|
-
end
|
416
|
+
class Ellipsoid < Def
|
418
417
|
|
418
|
+
# Returns ellipsoid definition as string in format '#<Proj4::Ellipsoid id="...", major="...", ell="...", name="...">'.
|
419
|
+
#
|
420
|
+
# call-seq: inspect -> String
|
421
|
+
#
|
422
|
+
def inspect
|
423
|
+
"#<Proj4::Ellipsoid id=\"#{id}\", major=\"#{major}\", ell=\"#{ell}\", name=\"#{name}\">"
|
419
424
|
end
|
420
425
|
|
421
|
-
|
426
|
+
end
|
422
427
|
|
423
|
-
|
424
|
-
#
|
425
|
-
# call-seq: inspect -> String
|
426
|
-
#
|
427
|
-
def inspect
|
428
|
-
"#<Proj4::PrimeMeridian id=\"#{id}\", defn=\"#{defn}\">"
|
429
|
-
end
|
428
|
+
class PrimeMeridian < Def
|
430
429
|
|
430
|
+
# Returns a prime meridian definition as string in format '#<Proj4::PrimeMeridian id="...", defn="...">'.
|
431
|
+
#
|
432
|
+
# call-seq: inspect -> String
|
433
|
+
#
|
434
|
+
def inspect
|
435
|
+
"#<Proj4::PrimeMeridian id=\"#{id}\", defn=\"#{defn}\">"
|
431
436
|
end
|
432
437
|
|
433
|
-
|
438
|
+
end
|
434
439
|
|
435
|
-
|
436
|
-
#
|
437
|
-
# call-seq: inspect -> String
|
438
|
-
#
|
439
|
-
def inspect
|
440
|
-
"#<Proj4::ProjectionType id=\"#{id}\", name=\"#{name}\">"
|
441
|
-
end
|
440
|
+
class ProjectionType < Def
|
442
441
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
442
|
+
# Returns a projection type as string in format '#<Proj4::PrimeMeridian id="...", name="...">'.
|
443
|
+
#
|
444
|
+
# call-seq: inspect -> String
|
445
|
+
#
|
446
|
+
def inspect
|
447
|
+
"#<Proj4::ProjectionType id=\"#{id}\", name=\"#{name}\">"
|
448
|
+
end
|
450
449
|
|
450
|
+
# Gets name of this projection type.
|
451
|
+
#
|
452
|
+
# call-seq: name -> String
|
453
|
+
#
|
454
|
+
def name
|
455
|
+
descr.sub(/\n.*/m, '')
|
451
456
|
end
|
452
457
|
|
453
|
-
|
458
|
+
end
|
454
459
|
|
455
|
-
|
456
|
-
#
|
457
|
-
# call-seq: inspect -> String
|
458
|
-
#
|
459
|
-
def inspect
|
460
|
-
"#<Proj4::Unit id=\"#{id}\", to_meter=\"#{to_meter}\", name=\"#{name}\">"
|
461
|
-
end
|
460
|
+
class Unit < Def
|
462
461
|
|
462
|
+
# Returns unit definition as string in format '#<Proj4::Unit id="...", to_meter="...", name="...">'.
|
463
|
+
#
|
464
|
+
# call-seq: inspect -> String
|
465
|
+
#
|
466
|
+
def inspect
|
467
|
+
"#<Proj4::Unit id=\"#{id}\", to_meter=\"#{to_meter}\", name=\"#{name}\">"
|
463
468
|
end
|
464
469
|
|
470
|
+
end
|
471
|
+
|
465
472
|
end
|
466
473
|
|