Class: RGeo::CoordSys::Proj4

Inherits:
CS::CoordinateSystem show all
Defined in:
lib/rgeo/coord_sys/proj4.rb,
ext/proj4_c_impl/main.c

Overview

This is a Ruby wrapper around a Proj4 coordinate system. It represents a single geographic coordinate system, which may be a flat projection, a geocentric (3-dimensional) coordinate system, or a geographic (latitude-longitude) coordinate system.

Generally, these are used to define the projection for a Feature::Factory. You can then convert between coordinate systems by casting geometries between such factories using the :project option. You may also use this object directly to perform low-level coordinate transformations.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#dimensionObject

Returns the value of attribute dimension.



23
24
25
# File 'lib/rgeo/coord_sys/proj4.rb', line 23

def dimension
  @dimension
end

Class Method Details

._create(str, uses_radians) ⇒ Object



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'ext/proj4_c_impl/main.c', line 413

static VALUE cmethod_proj4_create(VALUE klass, VALUE str, VALUE uses_radians) {
  VALUE result;
  RGeo_Proj4Data *data;

  result = Qnil;
  Check_Type(str, T_STRING);
  data = ALLOC(RGeo_Proj4Data);
  if (data) {
    data->pj = proj_create(local_proj_context, StringValuePtr(str));
    data->original_str = str;
    data->uses_radians = RTEST(uses_radians) ? 1 : 0;
    result = TypedData_Wrap_Struct(klass, &rgeo_proj4_data_type, data);
  }
  return result;
}

._proj_versionObject



408
409
410
411
# File 'ext/proj4_c_impl/main.c', line 408

static VALUE cmethod_proj4_version(VALUE module) {
  return rb_sprintf("%d.%d.%d", PROJ_VERSION_MAJOR, PROJ_VERSION_MINOR,
                    PROJ_VERSION_PATCH);
}

.create(defn_, opts_ = {}) ⇒ Object Also known as: create_from_wkt

Create a new Proj4 object, given a definition, which may be either a string, hash, or integer. If an integer is given, it assumes that you are using the EPSG SRID that matches that code. Returns nil if the given definition is invalid or Proj4 is not supported.

Recognized options include:

:radians

If set to true, then this proj4 will represent geographic (latitude/longitude) coordinates in radians rather than degrees. If this is a geographic coordinate system, then its units will be in radians. If this is a projected coordinate system, then its units will be unchanged, but any geographic coordinate system obtained using get_geographic will use radians as its units. If this is a geocentric or other type of coordinate system, this has no effect. Default is false. (That is all coordinates are in degrees by default.)



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/rgeo/coord_sys/proj4.rb', line 240

def create(defn_, opts_ = {})
  result_ = nil
  if supported?
    if defn_.is_a?(::Hash)
      defn_ = defn_.map { |k_, v_| v_ ? "+#{k_}=#{v_}" : "+#{k_}" }.join(" ")
    end

    defn_ = "EPSG:#{defn_}" if defn_.is_a?(Integer)

    result_ = _create(defn_, opts_[:radians])
    raise RGeo::Error::InvalidProjection unless result_._valid?

    result_.dimension = result_._axis_count
  end
  result_
end

.new(defn_, opts_ = {}) ⇒ Object

Create a new Proj4 object, given a definition, which may be either a string or a hash. Raises Error::UnsupportedOperation if the given definition is invalid or Proj4 is not supported.

Recognized options include:

:radians

If set to true, then this proj4 will represent geographic (latitude/longitude) coordinates in radians rather than degrees. If this is a geographic coordinate system, then its units will be in radians. If this is a projected coordinate system, then its units will be unchanged, but any geographic coordinate system obtained using get_geographic will use radians as its units. If this is a geocentric or other type of coordinate system, this has no effect. Default is false. (That is all coordinates are in degrees by default.)

Raises:

  • (Error::UnsupportedOperation)


275
276
277
278
279
# File 'lib/rgeo/coord_sys/proj4.rb', line 275

def new(defn_, opts_ = {})
  result_ = create(defn_, opts_)
  raise Error::UnsupportedOperation, "Proj4 not supported in this installation" unless result_
  result_
end

.supported?Boolean

Returns true if Proj4 is supported in this installation. If this returns false, the other methods such as create will not work.

Returns:

  • (Boolean)


212
213
214
# File 'lib/rgeo/coord_sys/proj4.rb', line 212

def supported?
  respond_to?(:_create)
end

.transform(from_proj, from_geometry, to_proj, to_factory) ⇒ Object

Low-level geometry transform method. Transforms the given geometry between the given two projections. The resulting geometry is constructed using the to_factory. Any projections associated with the factories themselves are ignored.



295
296
297
298
# File 'lib/rgeo/coord_sys/proj4.rb', line 295

def transform(from_proj, from_geometry, to_proj, to_factory)
  crs_to_crs = CRSStore.get(from_proj, to_proj)
  crs_to_crs.transform(from_geometry, to_factory)
end

.transform_coords(from_proj, to_proj, x, y, z = nil) ⇒ Object

Low-level coordinate transform method. Transforms the given coordinate (x, y, [z]) from one proj4 coordinate system to another. Returns an array with either two or three elements.



285
286
287
288
# File 'lib/rgeo/coord_sys/proj4.rb', line 285

def transform_coords(from_proj, to_proj, x, y, z = nil)
  crs_to_crs = CRSStore.get(from_proj, to_proj)
  crs_to_crs.transform_coords(x, y, z)
end

.versionObject

Returns the Proj library version as an integer (example: 493). TODO: return as string of the format “x.y.z”.



218
219
220
# File 'lib/rgeo/coord_sys/proj4.rb', line 218

def version
  _proj_version
end

Instance Method Details

#_as_textObject



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'ext/proj4_c_impl/main.c', line 250

static VALUE method_proj4_wkt_str(VALUE self) {
  VALUE result;
  PJ *pj;
  const char *str;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    const char *const options[] = {"MULTILINE=NO", NULL};
    str = proj_as_wkt(local_proj_context, pj, WKT_TYPE, options);
    if (str) {
      result = rb_str_new2(str);
    }
  }
  return result;
}

#_auth_nameObject



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'ext/proj4_c_impl/main.c', line 269

static VALUE method_proj4_auth_name_str(VALUE self) {
  VALUE result;
  PJ *pj;
  const char *id;
  const char *auth;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    auth = proj_get_id_auth_name(pj, 0);
    id = proj_get_id_code(pj, 0);
    if (id && auth) {
      result = rb_sprintf("%s:%s", auth, id);
    }
  }
  return result;
}

#_axis_and_unit_info(dimension) ⇒ Object



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'ext/proj4_c_impl/main.c', line 289

static VALUE method_proj4_axis_and_unit_info_str(VALUE self, VALUE dimension) {
  VALUE result;
  int dimension_index;
  PJ *pj;
  PJ *pj_cs;
  const char *axis_info;
  const char *unit_name;
  RGeo_Proj4Data *data;

  Check_Type(dimension, T_FIXNUM);

  dimension_index = FIX2INT(dimension);
  result = Qnil;

  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    pj_cs = proj_crs_get_coordinate_system(local_proj_context, pj);
    if (pj_cs) {
      if (proj_cs_get_axis_info(local_proj_context, pj_cs, dimension_index,
                                &axis_info, NULL, NULL, NULL, &unit_name, NULL,
                                NULL)) {
        result = rb_sprintf("%s:%s", axis_info, unit_name);
      }

      proj_destroy(pj_cs);
    }
  }
  return result;
}

#_axis_countObject



320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'ext/proj4_c_impl/main.c', line 320

static VALUE method_proj4_axis_count(VALUE self) {
  VALUE result;
  PJ *pj;
  PJ *pj_cs;
  int count;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    pj_cs = proj_crs_get_coordinate_system(local_proj_context, pj);
    if (pj_cs) {
      count = proj_cs_get_axis_count(local_proj_context, pj_cs);
      result = INT2FIX(count);

      proj_destroy(pj_cs);
    }
  }
  return result;
}

#_canonical_strObject



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'ext/proj4_c_impl/main.c', line 232

static VALUE method_proj4_canonical_str(VALUE self) {
  VALUE result;
  PJ *pj;
  const char *str;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    str = proj_as_proj_string(local_proj_context, pj, PJ_PROJ_4, NULL);
    if (str) {
      result = rb_str_new2(str);
    }
  }
  return result;
}

#_crs?Boolean

Returns:

  • (Boolean)


401
402
403
404
405
406
# File 'ext/proj4_c_impl/main.c', line 401

static VALUE method_proj4_is_crs(VALUE self) {
  RGeo_Proj4Data *self_data;

  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
  return proj_is_crs(self_data->pj) ? Qtrue : Qfalse;
}

#_geocentric?Boolean

Returns:

  • (Boolean)


363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'ext/proj4_c_impl/main.c', line 363

static VALUE method_proj4_is_geocentric(VALUE self) {
  VALUE result;
  PJ *pj;
  PJ_TYPE proj_type;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    proj_type = proj_get_type(pj);
    result = proj_type == PJ_TYPE_GEOCENTRIC_CRS ? Qtrue : Qfalse;
  }
  return result;
}

#_geographic?Boolean

Returns:

  • (Boolean)


342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'ext/proj4_c_impl/main.c', line 342

static VALUE method_proj4_is_geographic(VALUE self) {
  VALUE result;
  PJ *pj;
  PJ_TYPE proj_type;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    proj_type = proj_get_type(pj);
    if (proj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS ||
        proj_type == PJ_TYPE_GEOGRAPHIC_3D_CRS) {
      result = Qtrue;
    } else {
      result = Qfalse;
    }
  }
  return result;
}

#_get_geographicObject



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'ext/proj4_c_impl/main.c', line 190

static VALUE method_proj4_get_geographic(VALUE self) {
  VALUE result;
  RGeo_Proj4Data *new_data;
  RGeo_Proj4Data *self_data;
  PJ *geographic_proj;

  result = Qnil;
  new_data = ALLOC(RGeo_Proj4Data);
  if (new_data) {
    TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type,
                         self_data);

    geographic_proj =
        proj_crs_get_geodetic_crs(local_proj_context, self_data->pj);
    if (geographic_proj == 0) {
      FREE(new_data);
      rb_raise(rb_eRGeoInvalidProjectionError,
               "Geographic CRS could not be created because the source "
               "projection is not a CRS");
    }

    new_data->pj = geographic_proj;
    new_data->original_str = Qnil;
    new_data->uses_radians = self_data->uses_radians;
    result =
        TypedData_Wrap_Struct(CLASS_OF(self), &rgeo_proj4_data_type, new_data);
  }
  return result;
}

#_original_strObject



220
221
222
223
224
# File 'ext/proj4_c_impl/main.c', line 220

static VALUE method_proj4_original_str(VALUE self) {
  RGeo_Proj4Data *data;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  return data->original_str;
}

#_projected?Boolean

Returns:

  • (Boolean)


379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'ext/proj4_c_impl/main.c', line 379

static VALUE method_proj4_is_projected(VALUE self) {
  VALUE result;
  PJ *pj;
  PJ_TYPE proj_type;
  RGeo_Proj4Data *data;

  result = Qnil;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  pj = data->pj;
  if (pj) {
    proj_type = proj_get_type(pj);
    result = proj_type == PJ_TYPE_PROJECTED_CRS ? Qtrue : Qfalse;
  }
  return result;
}

#_radians?Boolean

Returns:

  • (Boolean)


226
227
228
229
230
# File 'ext/proj4_c_impl/main.c', line 226

static VALUE method_proj4_uses_radians(VALUE self) {
  RGeo_Proj4Data *data;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  return data->uses_radians ? Qtrue : Qfalse;
}

#_set_value(str, uses_radians) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'ext/proj4_c_impl/main.c', line 173

static VALUE method_proj4_set_value(VALUE self, VALUE str, VALUE uses_radians) {
  RGeo_Proj4Data *self_data;

  Check_Type(str, T_STRING);

  // Clear out any existing value
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
  rgeo_proj4_clear_struct(self_data);

  // Set new data
  self_data->pj = proj_create(local_proj_context, StringValuePtr(str));
  self_data->original_str = str;
  self_data->uses_radians = RTEST(uses_radians) ? 1 : 0;

  return self;
}

#_valid?Boolean

Returns:

  • (Boolean)


395
396
397
398
399
# File 'ext/proj4_c_impl/main.c', line 395

static VALUE method_proj4_is_valid(VALUE self) {
  RGeo_Proj4Data *data;
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, data);
  return data->pj ? Qtrue : Qfalse;
}

#as_textObject Also known as: to_wkt

Returns the WKT representation of the CRS.



112
113
114
# File 'lib/rgeo/coord_sys/proj4.rb', line 112

def as_text
  _as_text
end

#auth_nameObject

Returns the string representing the authority and code of the CRS if it exists, nil otherwise.

Ex. EPSG:4326



122
123
124
# File 'lib/rgeo/coord_sys/proj4.rb', line 122

def auth_name
  _auth_name
end

#authority_codeInteger|NilClass

Sometimes used to assign SRIDs in factory creation Also in the base CS::Info class that CS::CoordinateSystem inherits from

Returns:

  • (Integer|NilClass)

    authority code if available



186
187
188
# File 'lib/rgeo/coord_sys/proj4.rb', line 186

def authority_code
  auth_name.split(":")[1].to_i if auth_name
end

#canonical_hashObject

Returns the “canonical” hash definition for this coordinate system, as reported by Proj4. This may be slightly different from the definition used to construct this object.



92
93
94
95
96
97
98
99
100
# File 'lib/rgeo/coord_sys/proj4.rb', line 92

def canonical_hash
  unless defined?(@canonical_hash)
    @canonical_hash = {}
    canonical_str.strip.split(/\s+/).each do |elem_|
      @canonical_hash[Regexp.last_match(1)] = Regexp.last_match(3) if elem_ =~ /^\+(\w+)(=(\S+))?$/
    end
  end
  @canonical_hash
end

#canonical_strObject

Returns the “canonical” string definition for this coordinate system, as reported by Proj4. This may be slightly different from the definition used to construct this object.



80
81
82
83
84
85
86
# File 'lib/rgeo/coord_sys/proj4.rb', line 80

def canonical_str
  unless defined?(@canonical_str)
    @canonical_str = _canonical_str
    @canonical_str.force_encoding("US-ASCII") if @canonical_str.respond_to?(:force_encoding)
  end
  @canonical_str
end

#crs?Boolean

Returns true if this Proj4 object represents a CRS.

Returns:

  • (Boolean)


177
178
179
# File 'lib/rgeo/coord_sys/proj4.rb', line 177

def crs?
  _crs?
end

#encode_with(coder_) ⇒ Object

Psych support



63
64
65
66
# File 'lib/rgeo/coord_sys/proj4.rb', line 63

def encode_with(coder_) # :nodoc:
  coder_["proj4"] = original_str || canonical_str
  coder_["radians"] = radians?
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns true if this Proj4 is equivalent to the given Proj4.

Note: this tests for equivalence by comparing only the hash definitions of the Proj4 objects, and returning true if those definitions are equivalent. In some cases, this may still return false even if the actual coordinate systems are identical, since there are sometimes multiple ways to express a given coordinate system.

Returns:

  • (Boolean)


46
47
48
# File 'lib/rgeo/coord_sys/proj4.rb', line 46

def eql?(other)
  other.class == self.class && other.canonical_hash == canonical_hash && other._radians? == _radians?
end

#geocentric?Boolean

Returns true if this Proj4 object is a geocentric (3dz) coordinate system.

Returns:

  • (Boolean)


148
149
150
# File 'lib/rgeo/coord_sys/proj4.rb', line 148

def geocentric?
  _geocentric?
end

#geographic?Boolean

Returns true if this Proj4 object is a geographic (lat-long) coordinate system.

Returns:

  • (Boolean)


141
142
143
# File 'lib/rgeo/coord_sys/proj4.rb', line 141

def geographic?
  _geographic?
end

#get_axis(dimension) ⇒ Object

Gets axis details for dimension within coordinate system. Each dimension in the coordinate system has a corresponding axis.



128
129
130
# File 'lib/rgeo/coord_sys/proj4.rb', line 128

def get_axis(dimension)
  _axis_and_unit_info(dimension).split(":")[0]
end

#get_geographicObject Also known as: geographic_coordinate_system

Get the geographic (unprojected lat-long) coordinate system corresponding to this coordinate system; i.e. the one that uses the same ellipsoid and datum.



170
171
172
# File 'lib/rgeo/coord_sys/proj4.rb', line 170

def get_geographic
  _get_geographic
end

#get_units(dimension) ⇒ Object

Gets units for dimension within coordinate system. Each dimension in the coordinate system has corresponding units.



134
135
136
# File 'lib/rgeo/coord_sys/proj4.rb', line 134

def get_units(dimension)
  _axis_and_unit_info(dimension).split(":")[1]
end

#hashObject

:nodoc:



33
34
35
# File 'lib/rgeo/coord_sys/proj4.rb', line 33

def hash  # :nodoc:
  @hash ||= canonical_hash.hash
end

#init_with(coder_) ⇒ Object

:nodoc:



68
69
70
71
72
73
74
# File 'lib/rgeo/coord_sys/proj4.rb', line 68

def init_with(coder_) # :nodoc:
  if coder_.type == :scalar
    _set_value(coder_.scalar, false)
  else
    _set_value(coder_["proj4"], coder_["radians"])
  end
end

#initialize_copy(orig) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'ext/proj4_c_impl/main.c', line 148

static VALUE method_proj4_initialize_copy(VALUE self, VALUE orig) {
  RGeo_Proj4Data *self_data;
  RGeo_Proj4Data *orig_data;
  const char *str;

  // Clear out any existing value
  TypedData_Get_Struct(self, RGeo_Proj4Data, &rgeo_proj4_data_type, self_data);
  rgeo_proj4_clear_struct(self_data);

  // Copy value from orig
  TypedData_Get_Struct(orig, RGeo_Proj4Data, &rgeo_proj4_data_type, orig_data);
  if (!NIL_P(orig_data->original_str)) {
    self_data->pj = proj_create(local_proj_context,
                                StringValuePtr(orig_data->original_str));
  } else {
    str =
        proj_as_proj_string(local_proj_context, orig_data->pj, PJ_PROJ_4, NULL);
    self_data->pj = proj_create(local_proj_context, str);
  }
  self_data->original_str = orig_data->original_str;
  self_data->uses_radians = orig_data->uses_radians;

  return self;
}

#inspectObject

:nodoc:



25
26
27
# File 'lib/rgeo/coord_sys/proj4.rb', line 25

def inspect # :nodoc:
  "#<#{self.class}:0x#{object_id.to_s(16)} #{canonical_str.inspect}>"
end

#marshal_dumpObject

Marshal support



53
54
55
# File 'lib/rgeo/coord_sys/proj4.rb', line 53

def marshal_dump # :nodoc:
  { "rad" => radians?, "str" => original_str || canonical_str }
end

#marshal_load(data_) ⇒ Object

:nodoc:



57
58
59
# File 'lib/rgeo/coord_sys/proj4.rb', line 57

def marshal_load(data_) # :nodoc:
  _set_value(data_["str"], data_["rad"])
end

#original_strObject

Returns the string definition originally used to construct this object. Returns nil if this object wasn’t created by a string definition; i.e. if it was created using get_geographic.



106
107
108
# File 'lib/rgeo/coord_sys/proj4.rb', line 106

def original_str
  _original_str
end

#projected?Boolean

Returns true if this Proj4 object is a projected coordinate system

Returns:

  • (Boolean)


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

def projected?
  _projected?
end

#radians?Boolean

Returns true if this Proj4 object uses radians rather than degrees if it is a geographic coordinate system.

Returns:

  • (Boolean)


162
163
164
# File 'lib/rgeo/coord_sys/proj4.rb', line 162

def radians?
  _radians?
end

#to_sObject

:nodoc:



29
30
31
# File 'lib/rgeo/coord_sys/proj4.rb', line 29

def to_s  # :nodoc:
  canonical_str
end

#transform(from_geometry, to_proj, to_factory) ⇒ Object

Low-level geometry transform method. Transforms the given geometry between the given two projections. The resulting geometry is constructed using the to_factory. Any projections associated with the factories themselves are ignored.



203
204
205
# File 'lib/rgeo/coord_sys/proj4.rb', line 203

def transform(from_geometry, to_proj, to_factory)
  self.class.transform(self, from_geometry, to_proj, to_factory)
end

#transform_coords(to_proj, x, y, z = nil) ⇒ Object

Low-level coordinate transform method. Transforms the given coordinate (x, y, [z]) from one proj4 coordinate system to another. Returns an array with either two or three elements.



194
195
196
# File 'lib/rgeo/coord_sys/proj4.rb', line 194

def transform_coords(to_proj, x, y, z = nil)
  self.class.transform_coords(self, to_proj, x, y, z)
end