Class: Proj4::Projection

Inherits:
Object
  • Object
show all
Defined in:
lib/proj4.rb,
ext/projrb.c

Overview

The Projection class represents a geographical projection.

Creating a new projection object

Projection objects are created through the new method as usual. Depending on the kind of projection, many different parameters are needed. Please consult the documentation of the Proj.4 C library at trac.osgeo.org/proj/ for details.

There are several ways of specifying the parameters:

as a String:

A string with the parameters in ‘[+]key=value’ format concatenated together. This is the format used by the proj and cs2cs command line tool.

proj = Projection.new "+proj=utm +zone=21 +units=m"
as an Array:

An array with each parameter as a member in the array in ‘[+]key=value’ format.

proj = Projection.new [ "proj=utm", "zone=21", "units=m" ]
as a Hash:

A hash with strings or symbols as keys.

proj = Projection.new( "proj" => "utm", "zone" => "21", "units" => "m" )
proj = Projection.new( :proj => "utm", :zone => "21", :units => "m" )

With all variants the plus sign in front of the keys is optional.

Using a projection object to project points

There are two ways a projection can be used: Through the forward and inverse methods (with all their variants) you can do projection from longitudes and latitudes into the coordinate system used by the projection and back. These projections are always 2D, i.e. you need and get lon/lat or x/y coordinates.

The alternative is the transform method (with all its variants) which is used to transform 3D points from one projection and datum to another. In addition to the x/y coordinates the transform method also reads and returns a z coordinate.

Versions of the projection methods

All three projection methods (forward, inverse, and transform) work on points. Every method has an in-place version (with a name ending in !) which changes the given point and a normal version which first creates a copy of the point object and changes and returns that. All methods use radians when reading or returning points. For convenience there are also forwardDeg and inverseDeg methods (and in-place versions forwardDeg! and inverseDeg!) that will work with degrees.

Points

All projection method project points to other points. You can use objects of the Proj4::Point class for this or any other object which supports the x, y, z read and write accessor methods. (In fact you don’t even need the z accessor methods, 0 is assumed if they don’t exist.)

Some projection methods act on the given point in-place, other return a copy of the point object. But in any case all other attributes of the point object are retained.

Projection collections

The methods forward_all, inverse_all, and transform_all (and their in-place versions forward_all!, inverse_all!, and transform_all! work just like their simple counterparts, but instead of a single point they convert a collection of points in one go.

These methods all take an array as an argument or any object responding to the each method (for the in-place versions) or each, clear, and << methods (for the normal version).

Some projection methods act on the given collection in-place, i.e. the collection is not touched and all points in the collection will be projected in-place. The other methods act on a copy of the collection and on copies of each point in the collection. So you’ll get back a brand new copy of the collection with new copies of the points with the projected coordinates. In any case all other attributes of the collection and points are retained.

Instance Method Summary collapse

Constructor Details

#initialize(params) ⇒ Object

Creates a new projection object. See the intro for details.

call-seq: new(String) -> Proj4::Projection
          new(Array) -> Proj4::Projection
          new(Hash) -> Proj4::Projection


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'ext/projrb.c', line 77

static VALUE proj_initialize(VALUE self, VALUE params){
  _wrap_pj* wpj;
  VALUE proj_params = rb_funcall(cProjection, idParseInitParameters, 1, params);
  int size = RARRAY_LEN(proj_params);
  char** c_params = (char **) malloc(size*sizeof(char *));
  int i;

  for (i=0; i < size; i++)
  {
    VALUE item = rb_ary_entry(proj_params, i);
    c_params[i]= StringValuePtr(item); 
  }

  Data_Get_Struct(self,_wrap_pj,wpj);
  wpj->pj = pj_init(size,c_params);
  free(c_params);
  if(wpj->pj == 0) {
    int pj_errno_ref = *pj_get_errno_ref();
    if (pj_errno_ref > 0) {
        rb_raise(rb_eSystemCallError, "Unknown system call error");
    } else {
        raise_error(pj_errno_ref);
    }
  }
  return self;
}

Instance Method Details

#datumObject

Get the ID of the datum used in this projection.

call-seq: datum -> String



163
164
165
# File 'lib/proj4.rb', line 163

def datum
  getDef =~ /\+datum=(.+?) / ? $1 : nil
end

#forward(point) ⇒ Object

Forward projection of a point. Returns a copy of the point object with coordinates projected.

call-seq: forward(point) -> point



179
180
181
# File 'lib/proj4.rb', line 179

def forward(point)
  forward!(point.dup)
end

#forward!(point) ⇒ Object

Transforms a point in WGS84 LonLat in radians to projected coordinates.

This version of the method changes the point in-place.

call-seq: forward!(point) -> point


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'ext/projrb.c', line 156

static VALUE proj_forward(VALUE self,VALUE point){
  _wrap_pj* wpj;
  int pj_errno_ref;
  projLP pj_point;
  projXY pj_result;
  Data_Get_Struct(self,_wrap_pj,wpj);

  pj_point.u = NUM2DBL( rb_funcall(point, idGetX, 0) );
  pj_point.v = NUM2DBL( rb_funcall(point, idGetY, 0) );
  pj_result = pj_fwd(pj_point, wpj->pj);

  pj_errno_ref = *pj_get_errno_ref();
  if (pj_errno_ref == 0) {
    rb_funcall(point, idSetX, 1, rb_float_new(pj_result.u) );
    rb_funcall(point, idSetY, 1, rb_float_new(pj_result.v) );
    return point;
  } else if (pj_errno_ref > 0) {
    rb_raise(rb_eSystemCallError, "Unknown system call error");
  } else {
    raise_error(pj_errno_ref);
  }
  return self; /* Makes gcc happy */
}

#forward_all(collection) ⇒ Object

Projects all points in a collection. The collection object must implement the each, clear, and << methods (just like an Array) for this to work.

call-seq: forward_all(collection) -> collection



221
222
223
224
225
226
227
# File 'lib/proj4.rb', line 221

def forward_all(collection)
  newcollection = collection.dup.clear
  collection.each do |point|
    newcollection << forward(point)
  end
  newcollection
end

#forward_all!(collection) ⇒ Object

Project all points in a collection ‘in place’. The collection object must implement the each method for this to work.

call-seq: forward_all!(collection) -> collection



208
209
210
211
212
213
# File 'lib/proj4.rb', line 208

def forward_all!(collection)
  collection.each do |point|
    forward!(point)
  end
  collection
end

#forwardDeg(point) ⇒ Object

Convenience function for calculating a forward projection with degrees instead of radians.

call-seq: forwardDeg(point) -> point



187
188
189
# File 'lib/proj4.rb', line 187

def forwardDeg(point)
  forwardDeg!(point.dup)
end

#forwardDeg!(point) ⇒ Object

Convenience function for calculating a forward projection with degrees instead of radians. This version works in-place, i.e. the point objects content is overwritten.

call-seq: forwardDeg!(point) -> point



196
197
198
199
200
# File 'lib/proj4.rb', line 196

def forwardDeg!(point)
  point.x *= Proj4::DEG_TO_RAD
  point.y *= Proj4::DEG_TO_RAD
  forward!(point)
end

#getDefObject

Get the expanded definition of this projection as a string.

call-seq: getDef -> String


144
145
146
147
148
# File 'ext/projrb.c', line 144

static VALUE proj_get_def(VALUE self){
  _wrap_pj* wpj;
  Data_Get_Struct(self,_wrap_pj,wpj);
  return rb_str_new2(pj_get_def(wpj->pj, 0));
}

#hasInverse?Boolean

Has this projection an inverse?

call-seq: hasInverse? -> true or false

Returns:

  • (Boolean)


110
111
112
113
114
# File 'ext/projrb.c', line 110

static VALUE proj_has_inverse(VALUE self){
  _wrap_pj* wpj;
  Data_Get_Struct(self,_wrap_pj,wpj);
  return wpj->pj->inv ? Qtrue : Qfalse;
}

#inverse(point) ⇒ Object

Inverse projection of a point. Returns a copy of the point object with coordinates projected.

call-seq: inverse(point) -> point



233
234
235
# File 'lib/proj4.rb', line 233

def inverse(point)
  inverse!(point.dup)
end

#inverse!(point) ⇒ Object

Transforms a point in the coordinate system defined at initialization of the Projection object to WGS84 LonLat in radians.

This version of the method changes the point in-place.

call-seq: inverse!(point) -> point


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'ext/projrb.c', line 186

static VALUE proj_inverse(VALUE self,VALUE point){
  _wrap_pj* wpj;
  int pj_errno_ref;
  projXY pj_point;
  projLP pj_result;

  Data_Get_Struct(self,_wrap_pj,wpj);

  pj_point.u = NUM2DBL( rb_funcall(point, idGetX, 0) );
  pj_point.v = NUM2DBL( rb_funcall(point, idGetY, 0) );
  pj_result = pj_inv(pj_point, wpj->pj);

  pj_errno_ref = *pj_get_errno_ref();
  if (pj_errno_ref == 0) {
    rb_funcall(point, idSetX, 1, rb_float_new(pj_result.u) );
    rb_funcall(point, idSetY, 1, rb_float_new(pj_result.v) );
    return point;
  } else if (pj_errno_ref > 0) {
    rb_raise(rb_eSystemCallError, "Unknown system call error");
  } else {
    raise_error(pj_errno_ref);
  }
  return self; /* Makes gcc happy */
}

#inverse_all(collection) ⇒ Object

Projects all points in a collection. The collection object must implement the each, clear, and << methods (just like an Array) for this to work.

call-seq: inverse_all(collection) -> collection



276
277
278
279
280
281
282
# File 'lib/proj4.rb', line 276

def inverse_all(collection)
  newcollection = collection.dup.clear
  collection.each do |point|
    newcollection << inverse(point)
  end
  newcollection
end

#inverse_all!(collection) ⇒ Object

Project all points in a collection ‘in place’. The collection object must implement the each method for this to work.

call-seq: inverse_all!(collection) -> collection



263
264
265
266
267
268
# File 'lib/proj4.rb', line 263

def inverse_all!(collection)
  collection.each do |point|
    inverse!(point)
  end
  collection
end

#inverseDeg(point) ⇒ Object

Convenience function for calculating an inverse projection with the result in degrees instead of radians.

call-seq: inverseDeg(point) -> point



241
242
243
# File 'lib/proj4.rb', line 241

def inverseDeg(point)
  inverseDeg!(point.dup)
end

#inverseDeg!(point) ⇒ Object

Convenience function for calculating an inverse projection with the result in degrees instead of radians. This version works in-place, i.e. the point objects content is overwritten.

call-seq: inverseDeg!(point) -> point



250
251
252
253
254
255
# File 'lib/proj4.rb', line 250

def inverseDeg!(point)
  inverse!(point)
  point.x *= Proj4::RAD_TO_DEG
  point.y *= Proj4::RAD_TO_DEG
  point
end

#isGeocent?Boolean Also known as: isGeocentric?

Is this projection a geocentric projection?

call-seq: isGeocentric? -> true or false

Returns:

  • (Boolean)


133
134
135
136
137
# File 'ext/projrb.c', line 133

static VALUE proj_is_geocent(VALUE self){
  _wrap_pj* wpj;
  Data_Get_Struct(self,_wrap_pj,wpj);
  return pj_is_geocent(wpj->pj) ? Qtrue : Qfalse;
}

#isLatLong?Boolean

Is this projection a latlong projection?

call-seq: isLatLong? -> true or false

Returns:

  • (Boolean)


122
123
124
125
126
# File 'ext/projrb.c', line 122

static VALUE proj_is_latlong(VALUE self){
  _wrap_pj* wpj;
  Data_Get_Struct(self,_wrap_pj,wpj);
  return pj_is_latlong(wpj->pj) ? Qtrue : Qfalse;
}

#projectionObject

Get the ID of this projection.

call-seq: projection -> String



155
156
157
# File 'lib/proj4.rb', line 155

def projection
  getDef =~ /\+proj=(.+?) / ?  $1 : nil
end

#to_sObject

Get definition of projection in typical inspect format (#<Proj4::Projection init=… proj=… …>).

call-seq: to_s -> String



171
172
173
# File 'lib/proj4.rb', line 171

def to_s
  "#<Proj4::Projection#{ getDef }>"
end

#transform(otherProjection, point) ⇒ Object

Transforms a point from one projection to another.

call-seq: transform(destinationProjection, point) -> point



288
289
290
# File 'lib/proj4.rb', line 288

def transform(otherProjection, point)
  transform!(otherProjection, point.dup)
end

#transform!(dst, point) ⇒ Object

Transforms a point from one projection to another. The second parameter is

either a Proj4::Point object or you can use any object which
responds to the x, y, z read and write accessor methods. (In fact you
don't even need the z accessor methods, 0 is assumed if they don't exist).
This is the destructive variant of the method, i.e. it will overwrite your
existing point coordinates but otherwise leave the point object alone.

call-seq: transform!(destinationProjection, point) -> point


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'ext/projrb.c', line 221

static VALUE proj_transform(VALUE self, VALUE dst, VALUE point){
  _wrap_pj* wpjsrc;
  _wrap_pj* wpjdst;
  double array_x[1];
  double array_y[1];
  double array_z[1];
  int result;

  Data_Get_Struct(self,_wrap_pj,wpjsrc);
  Data_Get_Struct(dst,_wrap_pj,wpjdst);

  array_x[0] = NUM2DBL( rb_funcall(point, idGetX, 0) );
  array_y[0] = NUM2DBL( rb_funcall(point, idGetY, 0) );

  /* if point objects has a method 'z' we get the z coordinate, otherwise we just assume 0 */
  if ( rb_respond_to(point, idGetZ) ) {
    array_z[0] = NUM2DBL( rb_funcall(point, idGetZ, 0) );
  } else {
    array_z[0] = 0.0;
  }

  result = pj_transform(wpjsrc->pj, wpjdst->pj, 1, 1, array_x, array_y, array_z);
  if (! result) {
    rb_funcall(point, idSetX, 1, rb_float_new(array_x[0]) );
    rb_funcall(point, idSetY, 1, rb_float_new(array_y[0]) );
    /* if point objects has a method 'z=' we set the z coordinate, otherwise we ignore it  */
    if ( rb_respond_to(point, idSetZ) ) {
        rb_funcall(point, idSetZ, 1, rb_float_new(array_z[0]) );
    }
    return point;
  } else if (result > 0) {
    rb_raise(rb_eSystemCallError, "Unknown system call error");
  } else {
    raise_error(result);
  }
  return self; /* Makes gcc happy */
}

#transform_all(otherProjection, collection) ⇒ Object

Transforms all points in a collection from one projection to another. The collection object must implement the each, clear, and << methods (just like an Array) for this to work.

call-seq: transform_all(destinationProjection, collection) -> collection



311
312
313
314
315
316
317
# File 'lib/proj4.rb', line 311

def transform_all(otherProjection, collection)
  newcollection = collection.dup.clear
  collection.each do |point|
    newcollection << transform(otherProjection, point)
  end
  newcollection
end

#transform_all!(otherProjection, collection) ⇒ Object

Transforms all points in a collection ‘in place’ from one projection to another. The collection object must implement the each method for this to work.

call-seq: transform_all!(destinationProjection, collection) -> collection



298
299
300
301
302
303
# File 'lib/proj4.rb', line 298

def transform_all!(otherProjection, collection)
  collection.each do |point|
    transform!(otherProjection, point)
  end
  collection
end