proj4rb 0.2.0-universal-darwin8.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/proj4.rb ADDED
@@ -0,0 +1,518 @@
1
+ ENV['PROJ_LIB'] = File.dirname(__FILE__) + '/../data'
2
+ require 'projrb'
3
+
4
+ # Ruby bindings for the Proj.4 cartographic projection library (http://proj.maptools.org).
5
+ module Proj4
6
+
7
+ # Base class for all Proj.4 exceptions. Subclasses with the name <errorname>Error are available for each exception.
8
+ class Error < StandardError
9
+
10
+ # List of all Proj.4 errors.
11
+ #--
12
+ # (This list is created from the one in pj_strerrno.c in the Proj.4 distribution.)
13
+ #++
14
+ 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}
15
+
16
+ # Return list of all errors.
17
+ #
18
+ # call-seq: list -> Array
19
+ #
20
+ def self.list
21
+ ERRORS
22
+ end
23
+
24
+ # Return name of error with given number.
25
+ #
26
+ # call-seq: error(errnum) -> String
27
+ #
28
+ def self.error(errnum)
29
+ ERRORS[errnum.abs] || 'Unknown'
30
+ end
31
+
32
+ # Raise an error with error number +errnum+.
33
+ def self.raise_error(errnum)
34
+ raise eval("#{error(errnum.abs)}Error"), strerrno(-(errnum.abs)), caller[0..-1]
35
+ end
36
+
37
+ # Return error number of this error.
38
+ def errnum
39
+ self.class.errnum
40
+ end
41
+
42
+ end
43
+
44
+ Error.list.each_with_index do |err, index|
45
+ eval "class #{err}Error < Error;
46
+ def self.errnum;
47
+ #{index};
48
+ end;
49
+ end"
50
+ end
51
+
52
+ # The Projection class represents a geographical projection.
53
+ #
54
+ # = Creating a new projection object
55
+ #
56
+ # Projection objects are created through the new method as usual. Depending on the kind of projection, many
57
+ # different parameters are needed. Please consult the documentation of the Proj.4 C library at http://proj.maptools.org
58
+ # for details.
59
+ #
60
+ # There are several ways of specifying the parameters:
61
+ #
62
+ # [<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.
63
+ #
64
+ # proj = Projection.new "+proj=utm +zone=21 +units=m"
65
+ #
66
+ # [<b>as an Array:</b>] An array with each parameter as a member in the array in '[+]key=value' format.
67
+ #
68
+ # proj = Projection.new [ "proj=utm", "zone=21", "units=m" ]
69
+ #
70
+ # [<b>as a Hash:</b>] A hash with strings or symbols as keys.
71
+ #
72
+ # proj = Projection.new( "proj" => "utm", "zone" => "21", "units" => "m" )
73
+ # proj = Projection.new( :proj => "utm", :zone => "21", :units => "m" )
74
+ #
75
+ # With all variants the plus sign in front of the keys is optional.
76
+ #
77
+ # = Using a projection object to project points
78
+ #
79
+ # There are two ways a projection can be used: Through the +forward+ and +inverse+ methods (with all their variants)
80
+ # you can do projection from longitudes and latitudes into the coordinate system used by the projection and back.
81
+ # These projections are always 2D, i.e. you need and get lon/lat or x/y coordinates.
82
+ #
83
+ # The alternative is the +transform+ method (with all its variants) which is used to transform 3D points from one
84
+ # projection and datum to another. In addition to the x/y coordinates the transform method also reads and returns
85
+ # a z coordinate.
86
+ #
87
+ # = Versions of the projection methods
88
+ #
89
+ # All three projection methods (+forward+, +inverse+, and +transform+) work on points. Every method has an in-place
90
+ # version (with a name ending in !) which changes the given point and a normal version which first creates a copy of
91
+ # the point object and changes and returns that. All methods use radians when reading or returning points. For
92
+ # convenience there are also +forwardDeg+ and +inverseDeg+ methods (and in-place versions <tt>forwardDeg!</tt>
93
+ # and <tt>inverseDeg!</tt>) that will work with degrees.
94
+ #
95
+ # = Points
96
+ #
97
+ # All projection method project points to other points. You can use objects of the Proj4::Point class for this or
98
+ # any other object which supports the x, y, z read and write accessor methods. (In fact you don't even need the
99
+ # z accessor methods, 0 is assumed if they don't exist.)
100
+ #
101
+ # Some projection methods act on the given point in-place, other return a copy of the point object. But in any case
102
+ # all other attributes of the point object are retained.
103
+ #
104
+ # = Projection collections
105
+ #
106
+ # The methods forward_all, inverse_all, and transform_all (and their in-place versions forward_all!,
107
+ # inverse_all!, and transform_all! work just like their simple counterparts, but instead of a single
108
+ # point they convert a collection of points in one go.
109
+ #
110
+ # These methods all take an array as an argument or any object responding to the +each+ method (for the in-place versions)
111
+ # or +each+, +clear+, and <tt><<</tt> methods (for the normal version).
112
+ #
113
+ # Some projection methods act on the given collection in-place, i.e. the collection is not touched and all points
114
+ # in the collection will be projected in-place. The other methods act on a copy of the collection and on copies
115
+ # of each point in the collection. So you'll get back a brand new copy of the collection with new copies of the
116
+ # points with the projected coordinates. In any case all other attributes of the collection and points are retained.
117
+ #
118
+ class Projection
119
+
120
+ private
121
+
122
+ def self._parse_init_parameters(args)
123
+ case args
124
+ when Array
125
+ args.collect{ |a| a.sub(/^\+/, '') }
126
+ when String
127
+ args.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
128
+ when Hash
129
+ array = []
130
+ args.each_pair{ | key, value | array << (value.nil? ? key.to_s : "#{key}=#{value}") }
131
+ array
132
+ when Proj4::Projection
133
+ args.getDef.strip.split(' ').collect{ |a| a.sub(/^\+/, '')}
134
+ else
135
+ raise ArgumentError, "Unknown type #{args.class} for projection definition"
136
+ end
137
+ end
138
+
139
+ public
140
+
141
+ # Get the ID of this projection.
142
+ #
143
+ # call-seq: projection -> String
144
+ #
145
+ def projection
146
+ getDef =~ /\+proj=(.+?) / ? $1 : nil
147
+ end
148
+
149
+ # Get the ID of the datum used in this projection.
150
+ #
151
+ # call-seq: datum -> String
152
+ #
153
+ def datum
154
+ getDef =~ /\+datum=(.+?) / ? $1 : nil
155
+ end
156
+
157
+ # Get definition of projection in typical inspect format (#<Proj4::Projection +init=... +proj=... ...>).
158
+ #
159
+ # call-seq: to_s -> String
160
+ #
161
+ def to_s
162
+ "#<Proj4::Projection#{ getDef }>"
163
+ end
164
+
165
+ # Forward projection of a point. Returns a copy of the point object with coordinates projected.
166
+ #
167
+ # call-seq: forward(point) -> point
168
+ #
169
+ def forward(point)
170
+ forward!(point.dup)
171
+ end
172
+
173
+ # Convenience function for calculating a forward projection with degrees instead of radians.
174
+ #
175
+ # call-seq: forwardDeg(point) -> point
176
+ #
177
+ def forwardDeg(point)
178
+ forwardDeg!(point.dup)
179
+ end
180
+
181
+ # Convenience function for calculating a forward projection with degrees instead of radians.
182
+ # This version works in-place, i.e. the point objects content is overwritten.
183
+ #
184
+ # call-seq: forwardDeg!(point) -> point
185
+ #
186
+ def forwardDeg!(point)
187
+ point.x *= Proj4::DEG_TO_RAD
188
+ point.y *= Proj4::DEG_TO_RAD
189
+ forward!(point)
190
+ end
191
+
192
+ # Project all points in a collection 'in place'.
193
+ # The +collection+ object must implement the +each+
194
+ # method for this to work.
195
+ #
196
+ # call-seq: forward_all!(collection) -> collection
197
+ #
198
+ def forward_all!(collection)
199
+ collection.each do |point|
200
+ forward!(point)
201
+ end
202
+ collection
203
+ end
204
+
205
+ # Projects all points in a collection.
206
+ # The +collection+ object must implement the +each+,
207
+ # +clear+, and << methods (just like an Array) for this to work.
208
+ #
209
+ # call-seq: forward_all(collection) -> collection
210
+ #
211
+ def forward_all(collection)
212
+ newcollection = collection.dup.clear
213
+ collection.each do |point|
214
+ newcollection << forward(point)
215
+ end
216
+ newcollection
217
+ end
218
+
219
+ # Inverse projection of a point. Returns a copy of the point object with coordinates projected.
220
+ #
221
+ # call-seq: inverse(point) -> point
222
+ #
223
+ def inverse(point)
224
+ inverse!(point.dup)
225
+ end
226
+
227
+ # Convenience function for calculating an inverse projection with the result in degrees instead of radians.
228
+ #
229
+ # call-seq: inverseDeg(point) -> point
230
+ #
231
+ def inverseDeg(point)
232
+ inverseDeg!(point.dup)
233
+ end
234
+
235
+ # Convenience function for calculating an inverse projection with the result in degrees instead of radians.
236
+ # This version works in-place, i.e. the point objects content is overwritten.
237
+ #
238
+ # call-seq: inverseDeg!(point) -> point
239
+ #
240
+ def inverseDeg!(point)
241
+ inverse!(point)
242
+ point.x *= Proj4::RAD_TO_DEG
243
+ point.y *= Proj4::RAD_TO_DEG
244
+ point
245
+ end
246
+
247
+ # Project all points in a collection 'in place'.
248
+ # The +collection+ object must implement the +each+
249
+ # method for this to work.
250
+ #
251
+ # call-seq: inverse_all!(collection) -> collection
252
+ #
253
+ def inverse_all!(collection)
254
+ collection.each do |point|
255
+ inverse!(point)
256
+ end
257
+ collection
258
+ end
259
+
260
+ # Projects all points in a collection.
261
+ # The +collection+ object must implement the +each+,
262
+ # +clear+, and << methods (just like an Array) for this to work.
263
+ #
264
+ # call-seq: inverse_all(collection) -> collection
265
+ #
266
+ def inverse_all(collection)
267
+ newcollection = collection.dup.clear
268
+ collection.each do |point|
269
+ newcollection << inverse(point)
270
+ end
271
+ newcollection
272
+ end
273
+
274
+ # Transforms a point from one projection to another.
275
+ #
276
+ # call-seq: transform(destinationProjection, point) -> point
277
+ #
278
+ def transform(otherProjection, point)
279
+ transform!(otherProjection, point.dup)
280
+ end
281
+
282
+ # Transforms all points in a collection 'in place' from one projection
283
+ # to another. The +collection+ object must implement the +each+
284
+ # method for this to work.
285
+ #
286
+ # call-seq: transform_all!(destinationProjection, collection) -> collection
287
+ #
288
+ def transform_all!(otherProjection, collection)
289
+ collection.each do |point|
290
+ transform!(otherProjection, point)
291
+ end
292
+ collection
293
+ end
294
+
295
+ # Transforms all points in a collection from one projection to
296
+ # another. The +collection+ object must implement the +each+,
297
+ # +clear+, and << methods (just like an Array) for this to work.
298
+ #
299
+ # call-seq: transform_all(destinationProjection, collection) -> collection
300
+ #
301
+ def transform_all(otherProjection, collection)
302
+ newcollection = collection.dup.clear
303
+ collection.each do |point|
304
+ newcollection << transform(otherProjection, point)
305
+ end
306
+ newcollection
307
+ end
308
+
309
+ end
310
+
311
+ # This class represents a point in either lon/lat or projected x/y coordinates.
312
+ class Point
313
+
314
+ # X coordinate or longitude
315
+ attr_accessor :x
316
+
317
+ # Y coordinate or latitude
318
+ attr_accessor :y
319
+
320
+ # Z coordinate (height)
321
+ attr_accessor :z
322
+
323
+ # Create new Proj4::Point object from coordinates.
324
+ def initialize(x, y, z=0)
325
+ @x = x
326
+ @y = y
327
+ @z = z
328
+ end
329
+
330
+ # Get longitude/x coordinate.
331
+ def lon
332
+ x
333
+ end
334
+
335
+ # Get latitude/y coordinate.
336
+ def lat
337
+ y
338
+ end
339
+
340
+ # Set longitude/x coordinate.
341
+ def lon=(lon)
342
+ @x = lon
343
+ end
344
+
345
+ # Set latitude/y coordinate.
346
+ def lat=(lat)
347
+ @y = lat
348
+ end
349
+
350
+ end
351
+
352
+ # Abstract base class for several types of definitions: Proj4::Datum, Proj4::Ellipsoid, Proj4::PrimeMeridian, Proj4::ProjectionType, Proj4::Unit.
353
+ #
354
+ # Note that these classes only work if the version of the Proj.4 C library used is at least 449.
355
+ class Def
356
+
357
+ # Initialize function raises error. Definitions are always defined by the underlying Proj.4 library, you can't create them yourself.
358
+ def initialize # :nodoc:
359
+ raise TypeError, "You can't created objects of this type yourself."
360
+ end
361
+
362
+ # Get the definition with given id.
363
+ def self.get(id)
364
+ self.list.select{ |u| u.id == id }.first
365
+ end
366
+
367
+ # Compares definitions by comparing ids.
368
+ #
369
+ # call-seq: one == other -> true or false
370
+ #
371
+ def ==(other)
372
+ self.id == other.id
373
+ end
374
+
375
+ # Compares definitions by comparing ids.
376
+ #
377
+ # call-seq: one <=> other -> -1, 0, 1
378
+ #
379
+ def <=>(other)
380
+ self.id <=> other.id
381
+ end
382
+
383
+ # Stringify definition. Returns ID of this definition.
384
+ #
385
+ # call-seq: to_s -> String
386
+ #
387
+ def to_s
388
+ id
389
+ end
390
+
391
+ end
392
+
393
+ class Datum < Def
394
+
395
+ # Returns datum definition as string in format '#<Proj4::Datum id="...", ellipse_id="...", defn="...", comments="...">'.
396
+ #
397
+ # call-seq: inspect -> String
398
+ #
399
+ def inspect
400
+ "#<Proj4::Datum id=\"#{id}\", ellipse_id=\"#{ellipse_id}\", defn=\"#{defn}\", comments=\"#{comments}\">"
401
+ end
402
+
403
+ end
404
+
405
+ class Ellipsoid < Def
406
+
407
+ # Returns ellipsoid definition as string in format '#<Proj4::Ellipsoid id="...", major="...", ell="...", name="...">'.
408
+ #
409
+ # call-seq: inspect -> String
410
+ #
411
+ def inspect
412
+ "#<Proj4::Ellipsoid id=\"#{id}\", major=\"#{major}\", ell=\"#{ell}\", name=\"#{name}\">"
413
+ end
414
+
415
+ end
416
+
417
+ class PrimeMeridian < Def
418
+
419
+ # Returns a prime meridian definition as string in format '#<Proj4::PrimeMeridian id="...", defn="...">'.
420
+ #
421
+ # call-seq: inspect -> String
422
+ #
423
+ def inspect
424
+ "#<Proj4::PrimeMeridian id=\"#{id}\", defn=\"#{defn}\">"
425
+ end
426
+
427
+ end
428
+
429
+ class ProjectionType < Def
430
+
431
+ # Returns a projection type as string in format '#<Proj4::PrimeMeridian id="...", name="...">'.
432
+ #
433
+ # call-seq: inspect -> String
434
+ #
435
+ def inspect
436
+ "#<Proj4::ProjectionType id=\"#{id}\", name=\"#{name}\">"
437
+ end
438
+
439
+ # Gets name of this projection type.
440
+ #
441
+ # call-seq: name -> String
442
+ #
443
+ def name
444
+ descr.sub(/\n.*/m, '')
445
+ end
446
+
447
+ end
448
+
449
+ class Unit < Def
450
+
451
+ # Returns unit definition as string in format '#<Proj4::Unit id="...", to_meter="...", name="...">'.
452
+ #
453
+ # call-seq: inspect -> String
454
+ #
455
+ def inspect
456
+ "#<Proj4::Unit id=\"#{id}\", to_meter=\"#{to_meter}\", name=\"#{name}\">"
457
+ end
458
+
459
+ end
460
+
461
+ # The UV class holds one coordinate pair. Can be either lon/lat or x/y.
462
+ #
463
+ # This class is deprecated and it will disappear in a later version of this
464
+ # library. Use Proj4::Point instead (or any other class supporting x, y read and
465
+ # write accessor method.
466
+ class UV
467
+
468
+ attr_accessor :x, :y
469
+
470
+ def initialize(x, y)
471
+ warn 'Use of class Proj4::UV is deprecated. Please use Proj4::Point instead. See documentation for details.'
472
+ if ! x.kind_of?(Float) or ! y.kind_of?(Float)
473
+ raise TypeError
474
+ end
475
+ @x = x
476
+ @y = y
477
+ end
478
+
479
+ # get u(x) coordinate
480
+ def u
481
+ x
482
+ end
483
+
484
+ # get v(y) coordinate
485
+ def v
486
+ y
487
+ end
488
+
489
+ # set u(x) coordinate
490
+ def u=(u)
491
+ @x = u
492
+ end
493
+
494
+ # set v(y) coordinate
495
+ def v=(v)
496
+ @y = v
497
+ end
498
+
499
+ # Compare to UV instances, they are equal if both coordinates are equal, respectively.
500
+ #
501
+ # call-seq: uv == other -> true or false
502
+ #
503
+ def ==(uv)
504
+ self.u == uv.u && self.v == uv.v
505
+ end
506
+
507
+ # Create string in format 'x,y'.
508
+ #
509
+ # call-seq: to_s -> String
510
+ #
511
+ def to_s
512
+ "#{u},#{v}"
513
+ end
514
+
515
+ end
516
+
517
+ end
518
+
data/lib/projrb.bundle ADDED
Binary file
data/rakefile.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/clean'
6
+
7
+ task :default => :test
8
+
9
+ CLOBBER.include('pkg/*', 'proj4rb-doc/**/*', 'lib/*.so', 'lib/*.bundle', 'lib/*.dll', 'src/*.o', 'src/*.so', 'src/*.bundle', 'src/*.dll', 'src/Makefile', 'src/mkmf.log')
10
+
11
+ desc "Create Makefile"
12
+ file 'src/Makefile' => ['src/extconf.rb'] do
13
+ sh 'cd src; ruby extconf.rb'
14
+ end
15
+
16
+ desc "Build from C library"
17
+ task :build => ['src/Makefile', 'src/projrb.c'] do
18
+ sh 'cd src; make'
19
+ # Try the different suffixes for Linux, Mac OS X, or Windows shared libraries and put the one found into lib dir
20
+ ['so', 'bundle', 'dll'].each do |suffix|
21
+ if File.exists?('src/projrb.' + suffix)
22
+ puts "Copying 'src/projrb.#{suffix}' to lib/"
23
+ File.copy('src/projrb.' + suffix, 'lib/projrb.' + suffix)
24
+ end
25
+ end
26
+ end
27
+
28
+ desc "Run the tests"
29
+ Rake::TestTask::new do |t|
30
+ t.test_files = FileList['test/test*.rb']
31
+ t.verbose = true
32
+ end
33
+
34
+ desc "Generate the documentation"
35
+ Rake::RDocTask::new do |rdoc|
36
+ rdoc.rdoc_dir = 'proj4rb-doc/'
37
+ rdoc.title = "Proj4rb Documentation"
38
+ rdoc.options << '--line-numbers' << '--inline-source'
39
+ rdoc.rdoc_files.include('README')
40
+ rdoc.rdoc_files.include('src/**/*.c', 'lib/proj4.rb')
41
+ end
42
+
43
+ spec = Gem::Specification::new do |s|
44
+ s.platform = Gem::Platform::CURRENT
45
+
46
+ s.name = 'proj4rb'
47
+ s.version = "0.2.0"
48
+ s.summary = "Ruby bindings for the Proj.4 Carthographic Projection library"
49
+ s.description = <<EOF
50
+ Proj4rb is a ruby binding for the Proj.4 Carthographic Projection library, that supports conversions between a very large number of geographic coordinate systems and datums.
51
+ EOF
52
+ s.author = 'Guilhem Vellut'
53
+ s.email = 'guilhem.vellut@gmail.com'
54
+ s.homepage = 'http://thepochisuperstarmegashow.com'
55
+ s.rubyforge_project = 'proj4rb'
56
+
57
+ s.requirements << 'Proj.4 C library'
58
+ s.require_path = 'lib'
59
+ s.files = FileList["lib/**/*.rb", "lib/**/*.dll","lib/**/*.so","lib/**/*.bundle","example/**/*.rb","src/extconf.rb","src/**/*.h","src/**/*.c","test/**/*.rb", "README","MIT-LICENSE","rakefile.rb"]
60
+ s.test_files = FileList['test/test*.rb']
61
+
62
+ s.has_rdoc = true
63
+ s.extra_rdoc_files = ["README"]
64
+ s.rdoc_options.concat ['--main', 'README']
65
+ end
66
+
67
+ desc "Package the library as a gem"
68
+ Rake::GemPackageTask.new(spec) do |pkg|
69
+ pkg.need_zip = true
70
+ pkg.need_tar = true
71
+ end
72
+
data/src/extconf.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+
3
+ # help with compiling on Mac OS X
4
+ $CFLAGS += " -I/sw/include"
5
+ $LDFLAGS += " -L/sw/lib"
6
+
7
+ have_library 'proj', 'pj_init'
8
+ create_makefile 'projrb'