Class: Proj::PjObject

Inherits:
Object
  • Object
show all
Defined in:
lib/proj/pj_object.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pointer, context = nil) ⇒ PjObject

Returns a new instance of PjObject.



193
194
195
196
197
198
199
200
# File 'lib/proj/pj_object.rb', line 193

def initialize(pointer, context=nil)
  if pointer.null?
    raise(Error, "Cannot create a PjObject with a null pointer")
  end
  @pointer = pointer
  @context = context || Context.current
  ObjectSpace.define_finalizer(self, self.class.finalize(@pointer, @context))
end

Class Method Details

.create(value, context = nil) ⇒ PjObject

Instantiates an object from a string

Examples:

conversion = Proj::Conversion.create("+proj=helmert")

Parameters:

  • value (String)

    Can be:

    • Proj string

    • WKT string

    • Object code (like “EPSG:4326”, “urn:ogc:def:crs:EPSG::4326”, “urn:ogc:def:coordinateOperation:EPSG::1671”),

    • Object name. e.g “WGS 84”, “WGS 84 / UTM zone 31N”. In that case as uniqueness is not guaranteed, heuristics are applied to determine the appropriate best match.

    • OGC URN combining references for compound coordinate reference systems (e.g “urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717” or custom abbreviated syntax “EPSG:2393+5717”),

    • OGC URN combining references for concatenated operations (e.g. “urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618”)

    • PROJJSON string. The jsonschema is at proj.org/schemas/v0.4/projjson.schema.json (added in 6.2)

    • compound CRS made from two object names separated with “ + ”. e.g. “WGS 84 + EGM96 height” (added in 7.1)

Returns:

See Also:



67
68
69
70
71
72
73
74
75
# File 'lib/proj/pj_object.rb', line 67

def self.create(value, context=nil)
  ptr = Api.proj_create(context || Context.current, value)

  if ptr.null?
    Error.check_object(self)
  end

  create_object(ptr, context)
end

.create_from_database(auth_name, code, category, use_alternative_grid_names = false, context = nil) ⇒ PjObject

Instantiates an object from a database lookup

Examples:

crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)

Parameters:

  • auth_name (String)

    Authority name (must not be nil)

  • code (String)

    Object code (must not be nil)

  • category (PjCategory)

    A PjCategory enum value

  • use_alternative_grid_names (Boolean) (defaults to: false)

    Whether PROJ alternative grid names should be substituted to the official grid names. Only used on transformations. Defaults to false

  • context (Context) (defaults to: nil)

    Context. If nil the current context is used

Returns:

See Also:



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/proj/pj_object.rb', line 91

def self.create_from_database(auth_name, code, category, use_alternative_grid_names = false, context = nil)
  context ||= Context.current
  ptr = Api.proj_create_from_database(context, auth_name, code, category,
                                      use_alternative_grid_names ? 1 : 0, nil)

  if ptr.null?
    Error.check_context(context)
  end

  create_object(ptr, context)
end

.create_from_name(name, context, auth_name: nil, types: nil, approximate_match: false, limit: 0) ⇒ PjObjects

Return a list of objects by their name

Examples:

objects = Proj::PjObject.create_from_name("WGS 84", Context.current)

Parameters:

  • name (String)

    Search value, must be at least two characters

  • context (Context)

    Context. If nil the current context is used

  • auth_name (String) (defaults to: nil)

    Authority name or nil for all authorities. Default is nil

  • types (Array<PjType>) (defaults to: nil)

    Types of objects to search for or nil for all types. Default is nil

  • approximate_match (Boolean) (defaults to: false)

    Whether approximate name identification is allowed. Default is false

  • limit (Integer) (defaults to: 0)

    The maximum number of results to return, use 0 for all results. Default is 0

Returns:

See Also:



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/proj/pj_object.rb', line 118

def self.create_from_name(name, context, auth_name: nil, types: nil, approximate_match: false, limit: 0)
  if types
    types_ptr = FFI::MemoryPointer.new(Api::PjType.native_type, types.size)
    types_ptr.write_array_of_int(types.map { |symbol| Api::PjType[symbol]})
    types_count = types.size
  else
    types_ptr = nil
    types_count = 0
  end

  ptr = Api.proj_create_from_name(context, auth_name, name, types_ptr, types_count, approximate_match ? 1 : 0, limit, nil)
  PjObjects.new(ptr, context)
end

.create_from_wkt(wkt, context = nil, strict: false, unset_identifiers: nil) ⇒ PjObject

Instantiates an object from a WKT string.

Parameters:

  • wkt (String)

    WKT string (must not be nil)

  • context (Context) (defaults to: nil)

    Context. If nil the current context is used

  • strict (Boolean) (defaults to: false)

    Enables strict validation will be enabled. Default is false

  • unset_identifiers (Boolean) (defaults to: nil)

    When enabled object identifiers are unset when there is a contradiction between the definition from WKT and the one from the database. Defaults to nil because this option is only available in Proj 9+

Returns:

See Also:



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/proj/pj_object.rb', line 145

def self.create_from_wkt(wkt, context = nil, strict: false, unset_identifiers: nil)
  out_warnings = FFI::MemoryPointer.new(:pointer)
  out_grammar_errors = FFI::MemoryPointer.new(:pointer)

  # @param wkt_type [PjWktType] WKT version to output. Defaults to PJ_WKT2_2018
  # @param multiline [Boolean] Specifies if output span multiple lines. Defaults to true.
  # @param indentation_width [Integer] Specifies the indentation level. Defaults to 4.
  #
  # @return [String] wkt

  # Unset
  options_hash = {"STRICT": strict ? "YES" : "NO"}
  case unset_identifiers
  when TrueClass
    options_hash["UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF"] = "YES"
  when FalseClass
    options_hash["UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF"] = "NO"
  end
  options = Options.new(options_hash)

  ptr = Api.proj_create_from_wkt(context, wkt, options, out_warnings, out_grammar_errors)

  warnings = Strings.new(out_warnings.read_pointer)
  errors = Strings.new(out_grammar_errors.read_pointer)

  unless errors.empty?
    raise(RuntimeError, errors.join(". "))
  end

  unless warnings.empty?
    warn(warnings.join(". "))
  end

  create_object(ptr, context)
end

Instance Method Details

#accuracyFloat

Expected accuracy of the transformation. -1 if unknown



327
328
329
# File 'lib/proj/pj_object.rb', line 327

def accuracy
  self.info[:accuracy]
end

#area_of_useArea

Return the area of use of an object.

Returns:

  • (Area)

    In case of multiple usages, this will be the one of first usage.

See Also:



417
418
419
# File 'lib/proj/pj_object.rb', line 417

def area_of_use
  domains.first&.area_of_use
end

#auth(index = 0) ⇒ Object



389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/proj/pj_object.rb', line 389

def auth(index=0)
  auth_name = self.auth_name(index)
  code = self.id_code(index)

  if auth_name and code
    "#{self.auth_name(index)}:#{self.id_code(index)}"
  elsif auth_name
    auth_name
  elsif code
    code
  end
end

#auth_name(index = 0) ⇒ String

Returns the authority name / codespace of an identifier of an object.

Parameters:

  • index (Integer) (defaults to: 0)

    Index of the identifier. 0 is for the first identifier. Default is 0.

Returns:

  • (String)

See Also:



356
357
358
# File 'lib/proj/pj_object.rb', line 356

def auth_name(index=0)
  Api.proj_get_id_auth_name(self, index)&.force_encoding('UTF-8')
end

#contextObject



234
235
236
# File 'lib/proj/pj_object.rb', line 234

def context
  @context || Context.current
end

#context=(value) ⇒ Object

Assign a new context to this object

Parameters:

  • value (Context)

    The context to assign to this object



223
224
225
226
227
228
# File 'lib/proj/pj_object.rb', line 223

def context=(value)
  Api.proj_assign_context(self, value)
  @context = value
  ObjectSpace.undefine_finalizer(self)
  ObjectSpace.define_finalizer(self, self.class.finalize(@pointer, @context))
end

#definitionString

The proj-string that was used to create the PJ object with, e.g. “+proj=merc lat_0=24 lon_0=53 +ellps=WGS84”



309
310
311
# File 'lib/proj/pj_object.rb', line 309

def definition
  self.info[:definition] ? self.info[:definition].force_encoding('UTF-8') : nil
end

#deprecated?Boolean

Returns whether an object is deprecated

Returns:

  • (Boolean)

    True if the object is deprecated, otherwise false

See Also:



243
244
245
246
# File 'lib/proj/pj_object.rb', line 243

def deprecated?
  result = Api.proj_is_deprecated(self)
  result == 1 ? true : false
end

#descriptionString

Long description of the operation the PJ object is based on, e.g. “Mercator Cyl, Sph&Ell lat_ts=”



300
301
302
# File 'lib/proj/pj_object.rb', line 300

def description
  self.info[:description] ? self.info[:description].force_encoding('UTF-8') : nil
end

#destroyObject

Explicitly free the underlying PROJ object.



213
214
215
216
217
218
# File 'lib/proj/pj_object.rb', line 213

def destroy
  Api.proj_destroy(@pointer)
  @pointer = FFI::Pointer::NULL
  ObjectSpace.undefine_finalizer(self)
  nil
end

#domainsArray<Domain>

Returns all usage domains for this object. Each domain has a scope and geographic area of use.

Returns:

See Also:



408
409
410
# File 'lib/proj/pj_object.rb', line 408

def domains
  Domain.domains(self)
end

#equivalent_to?(other, comparison) ⇒ Boolean

Return whether two objects are equivalent. For versions 6.3.0 and higher the check may use using the proj database to check for name aliases

Parameters:

  • other (PjObject)

    Object to compare to

  • comparison (PjComparisonCriterion)

    Comparison criterion

Returns:

  • (Boolean)

    True if the objects are equivalent, otherwise false

See Also:



258
259
260
261
262
263
264
265
# File 'lib/proj/pj_object.rb', line 258

def equivalent_to?(other, comparison)
  result = if defined?(Api.proj_is_equivalent_to_with_ctx)
             Api.proj_is_equivalent_to_with_ctx(self.context, self, other, comparison)
           else
             Api.proj_is_equivalent_to(self, other, comparison)
           end
  result == 1 ? true : false
end

#errornoInteger

Returns the current error-state of this object

Returns:

  • (Integer)

    An non-zero error codes indicates an error either with the transformation setup or during a transformation

See Also:



272
273
274
# File 'lib/proj/pj_object.rb', line 272

def errorno
  Api.proj_errno(self)
end

#factors(coordinate) ⇒ PJ_FACTORS

Calculate various cartographic properties, such as scale factors, angular distortion and meridian convergence. Depending on the underlying projection values will be calculated either numerically (default) or analytically. The function also calculates the partial derivatives of the given coordinate.

Parameters:

  • coordinate (Coordinate)

    Input geodetic coordinate in radians

Returns:

  • (PJ_FACTORS)

See Also:



452
453
454
# File 'lib/proj/pj_object.rb', line 452

def factors(coordinate)
  Api.proj_factors(self, coordinate)
end

#geod_direct(coord, azi1, s12) ⇒ Coordinate

Compute the endpoint from a start point, initial azimuth, and distance.

Parameters:

  • coord (Coordinate)

    Start coordinate (lon/lat in radians)

  • azi1 (Float)

    Forward azimuth at the start point (radians)

  • s12 (Float)

    Distance from the start point (meters)

Returns:

  • (Coordinate)

    Endpoint coordinate and reverse azimuth

See Also:



525
526
527
528
# File 'lib/proj/pj_object.rb', line 525

def geod_direct(coord, azi1, s12)
  ptr = Api.proj_geod_direct(self, coord, azi1, s12)
  Coordinate.from_coord(ptr)
end

#geod_distance(coord1, coord2) ⇒ Coordinate

Calculate the geodesic distance as well as forward and reverse azimuth between two points on the ellipsoid.

Note that the axis order of the transformation object is not taken into account, so even though a CRS object comes with axis ordering latitude/longitude coordinates used in this function should be reordered as longitude/latitude.

the second is the forward azimuth, the third value the reverse azimuth and the fourth value is unused.

Parameters:

  • coord1 (Coordinate)

    Coordinate of first point. Must be lat/long in radians

  • coord2 (Coordinate)

    Coordinate of second point. Must be lat/long in radians

Returns:

  • (Coordinate)

    The first value is the distance between coord1 and coord2 in meters,

See Also:



511
512
513
514
# File 'lib/proj/pj_object.rb', line 511

def geod_distance(coord1, coord2)
  ptr = Api.proj_geod(self, coord1, coord2)
  Coordinate.from_coord(ptr)
end

#has_inverse?Boolean

Returns true if an an inverse mapping of the defined operation exists, otherwise false



318
319
320
# File 'lib/proj/pj_object.rb', line 318

def has_inverse?
  self.info[:has_inverse] == 1 ? true : false
end

#idString

Short ID of the operation the PJ object is based on, that is, what comes after the +proj= in a proj-string, e.g. “merc”.



291
292
293
# File 'lib/proj/pj_object.rb', line 291

def id
  self.info[:id]
end

#id_code(index = 0) ⇒ String

Get the code of an identifier of an object

Parameters:

  • index (Integer) (defaults to: 0)

    Index of the identifier. 0 is the first identifier. Default is 0

Returns:

  • (String)

    The code or nil in case of error or missing name

See Also:



367
368
369
# File 'lib/proj/pj_object.rb', line 367

def id_code(index=0)
  Api.proj_get_id_code(self, index)
end

#infoPjProjInfo

Get information about this object



281
282
283
# File 'lib/proj/pj_object.rb', line 281

def info
  Api.proj_pj_info(self)
end

#initialize_copy(original) ⇒ Object



202
203
204
205
206
207
208
209
210
# File 'lib/proj/pj_object.rb', line 202

def initialize_copy(original)
  ObjectSpace.undefine_finalizer(self)

  super

  @pointer = Api.proj_clone(original.context, original)

  ObjectSpace.define_finalizer(self, self.class.finalize(@pointer, @context))
end

#lp_distance(coord1, coord2) ⇒ Float

Calculate geodesic distance between two points in geodetic coordinates. The calculated distance is between the two points located on the ellipsoid. Note that the axis order of the transformation object is not taken into account, so even though a CRS object comes with axis ordering latitude/longitude coordinates used in this function should be reordered as longitude/latitude.

Parameters:

  • coord1 (Coordinate)

    Coordinate of first point. Must be lat/long in radians

  • coord2 (Coordinate)

    Coordinate of second point. Must be lat/long in radians

Returns:

  • (Float)

    Distance between the coordinates in meters

See Also:



477
478
479
# File 'lib/proj/pj_object.rb', line 477

def lp_distance(coord1, coord2)
  Api.proj_lp_dist(self, coord1, coord2)
end

#lpz_distance(coord1, coord2) ⇒ Float

Calculate geodesic distance between two points in geodetic coordinates. Similar to PjObject#lp_distance but also takes the height above the ellipsoid into account.

Note that the axis order of the transformation object is not taken into account, so even though a CRS object comes with axis ordering latitude/longitude coordinates used in this function should be reordered as longitude/latitude.

Parameters:

  • coord1 (Coordinate)

    Coordinate of first point. Must be lat/long in radians

  • coord2 (Coordinate)

    Coordinate of second point. Must be lat/long in radians

Returns:

  • (Float)

    Distance between the coordinates in meters

See Also:



494
495
496
# File 'lib/proj/pj_object.rb', line 494

def lpz_distance(coord1, coord2)
  Api.proj_lpz_dist(self, coord1, coord2)
end

#nameString

Returns the name of an object



345
346
347
# File 'lib/proj/pj_object.rb', line 345

def name
  Api.proj_get_name(self)&.force_encoding('UTF-8')
end

#non_deprecatedArray

Return a list of non-deprecated objects related to the passed one



461
462
463
464
# File 'lib/proj/pj_object.rb', line 461

def non_deprecated
  ptr = Api.proj_get_non_deprecated(self.context, self)
  PjObjects.new(ptr, self.context)
end

#proj_typePjType

Return the type of an object



336
337
338
# File 'lib/proj/pj_object.rb', line 336

def proj_type
  Api.proj_get_type(self)
end

#remarksString

Get the remarks of an object

Returns:

  • (String)

    Remarks or nil in case of error

See Also:



376
377
378
# File 'lib/proj/pj_object.rb', line 376

def remarks
  Api.proj_get_remarks(self)
end

#scopeString

Get the scope of an object.

Returns:

  • (String)

    Scope or nil in case of error or a missing scope

See Also:



385
386
387
# File 'lib/proj/pj_object.rb', line 385

def scope
  domains.first&.scope
end

#source_crsCrs

Return the base CRS of a BoundCRS or a DerivedCRS/ProjectedCRS, or the source CRS of a CoordinateOperation, or the CRS of a CoordinateMetadata.



427
428
429
430
# File 'lib/proj/pj_object.rb', line 427

def source_crs
  ptr = Api.proj_get_source_crs(self.context, self)
  self.class.create_object(ptr, self.context)
end

#target_crsCrs

Return the hub CRS of a BoundCRS or the target CRS of a CoordinateOperation



437
438
439
440
# File 'lib/proj/pj_object.rb', line 437

def target_crs
  ptr = Api.proj_get_target_crs(self.context, self)
  self.class.create_object(ptr, self.context)
end

#to_json(multiline: true, indentation_width: 2) ⇒ String

Returns the json representation for this object

Parameters:

  • multiline (Boolean) (defaults to: true)

    Specifies if output span multiple lines. Defaults to true.

  • indentation_width (Integer) (defaults to: 2)

    Specifies the indentation level. Defaults to 2.

Returns:

  • (String)

See Also:



560
561
562
563
564
565
# File 'lib/proj/pj_object.rb', line 560

def to_json(multiline: true, indentation_width: 2)
  options = Options.new("MULTILINE": multiline ? "YES" : "NO",
                        "INDENTATION_WIDTH": indentation_width)

  Api.proj_as_projjson(self.context, self, options).force_encoding('UTF-8')
end

#to_proj_string(proj_version = :PJ_PROJ_5, use_approx_tmerc: false, multiline: false, indentation_width: 2, max_line_length: 80) ⇒ String

Returns the proj representation string for this object

Parameters:

  • proj_version (PjProjStringType) (defaults to: :PJ_PROJ_5)

    The proj version. Defaults to :PJ_PROJ_5

  • use_approx_tmerc (Boolean) (defaults to: false)

    True adds the approx flag to proj=tmerc or +proj=utm. Defaults to false

  • multiline (Boolean) (defaults to: false)

    Specifies if output span multiple lines. Defaults to false.

  • indentation_width (Integer) (defaults to: 2)

    Specifies the indentation level. Defaults to 2.

  • max_line_length (Integer) (defaults to: 80)

    Specifies the max line length level. Defaults to 80.

Returns:

  • (String)

See Also:



541
542
543
544
545
546
547
548
549
550
# File 'lib/proj/pj_object.rb', line 541

def to_proj_string(proj_version=:PJ_PROJ_5, use_approx_tmerc: false, multiline: false,
                                            indentation_width: 2, max_line_length: 80)

  options = Options.new("USE_APPROX_TMERC": use_approx_tmerc ? "YES" : "NO",
                        "MULTILINE": multiline ? "YES" : "NO",
                        "INDENTATION_WIDTH": indentation_width,
                        "MAX_LINE_LENGTH": max_line_length)

  Api.proj_as_proj_string(self.context, self, proj_version, options).force_encoding('UTF-8')
end

#to_ptrObject



230
231
232
# File 'lib/proj/pj_object.rb', line 230

def to_ptr
  @pointer
end

#to_sString

Returns the string representation for this object

Returns:

  • (String)

    String



595
596
597
# File 'lib/proj/pj_object.rb', line 595

def to_s
  "#<#{self.class.name} - #{name}, #{proj_type}>"
end

#to_wkt(wkt_type = :PJ_WKT2_2019, multiline: true, indentation_width: 4) ⇒ String

Returns the wkt representation for this object

Parameters:

  • wkt_type (PjWktType) (defaults to: :PJ_WKT2_2019)

    WKT version to output. Defaults to PJ_WKT2_2018

  • multiline (Boolean) (defaults to: true)

    Specifies if output span multiple lines. Defaults to true.

  • indentation_width (Integer) (defaults to: 4)

    Specifies the indentation level. Defaults to 4.

Returns:

  • (String)

    wkt

See Also:



576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/proj/pj_object.rb', line 576

def to_wkt(wkt_type=:PJ_WKT2_2019, multiline: true, indentation_width: 4)
  options = Options.new("MULTILINE": multiline ? "YES" : "NO",
                        "INDENTATION_WIDTH": indentation_width,
                        "OUTPUT_AXIS": "AUTO",
                        "STRICT": "YES",
                        "ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS": "NO")

  result = Api.proj_as_wkt(self.context, self, wkt_type, options)

  if result.nil?
    Error.check_object(self)
  end

  result.force_encoding('UTF-8')
end