proj4rb 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog +26 -15
- data/README.rdoc +82 -44
- data/Rakefile +27 -27
- data/lib/api/api.rb +96 -118
- data/lib/api/api_5_0.rb +331 -300
- data/lib/api/api_5_1.rb +6 -6
- data/lib/api/api_5_2.rb +4 -4
- data/lib/api/api_6_0.rb +116 -14
- data/lib/api/api_6_1.rb +4 -4
- data/lib/api/api_6_2.rb +9 -6
- data/lib/api/api_6_3.rb +6 -0
- data/lib/api/api_7_0.rb +68 -0
- data/lib/api/api_7_1.rb +73 -0
- data/lib/api/api_7_2.rb +14 -0
- data/lib/api/api_8_0.rb +6 -0
- data/lib/api/api_8_1.rb +24 -0
- data/lib/api/api_8_2.rb +6 -0
- data/lib/api/api_9_1.rb +7 -0
- data/lib/api/api_9_2.rb +9 -0
- data/lib/api/api_experimental.rb +196 -0
- data/lib/proj/area.rb +73 -32
- data/lib/proj/axis_info.rb +44 -0
- data/lib/proj/bounds.rb +13 -0
- data/lib/proj/context.rb +174 -28
- data/lib/proj/conversion.rb +92 -0
- data/lib/proj/coordinate.rb +281 -197
- data/lib/proj/coordinate_operation_mixin.rb +381 -0
- data/lib/proj/coordinate_system.rb +137 -0
- data/lib/proj/crs.rb +672 -204
- data/lib/proj/crs_info.rb +47 -0
- data/lib/proj/database.rb +305 -0
- data/lib/proj/datum.rb +32 -0
- data/lib/proj/datum_ensemble.rb +34 -0
- data/lib/proj/ellipsoid.rb +77 -41
- data/lib/proj/error.rb +62 -9
- data/lib/proj/file_api.rb +166 -0
- data/lib/proj/grid.rb +121 -0
- data/lib/proj/grid_cache.rb +64 -0
- data/lib/proj/grid_info.rb +19 -0
- data/lib/proj/network_api.rb +92 -0
- data/lib/proj/operation.rb +42 -42
- data/lib/proj/operation_factory_context.rb +136 -0
- data/lib/proj/parameter.rb +38 -0
- data/lib/proj/parameters.rb +106 -0
- data/lib/proj/pj_object.rb +670 -80
- data/lib/proj/pj_objects.rb +44 -0
- data/lib/proj/prime_meridian.rb +65 -39
- data/lib/proj/projection.rb +698 -207
- data/lib/proj/session.rb +46 -0
- data/lib/proj/strings.rb +32 -0
- data/lib/proj/transformation.rb +101 -60
- data/lib/proj/unit.rb +108 -53
- data/lib/proj.rb +110 -9
- data/proj4rb.gemspec +5 -5
- data/test/abstract_test.rb +23 -1
- data/test/context_test.rb +172 -82
- data/test/conversion_test.rb +368 -0
- data/test/coordinate_system_test.rb +144 -0
- data/test/crs_test.rb +770 -71
- data/test/database_test.rb +360 -0
- data/test/datum_ensemble_test.rb +65 -0
- data/test/datum_test.rb +55 -0
- data/test/ellipsoid_test.rb +64 -18
- data/test/file_api_test.rb +66 -0
- data/test/grid_cache_test.rb +72 -0
- data/test/grid_test.rb +141 -0
- data/test/network_api_test.rb +45 -0
- data/test/operation_factory_context_test.rb +201 -0
- data/test/parameters_test.rb +40 -0
- data/test/pj_object_test.rb +179 -0
- data/test/prime_meridian_test.rb +76 -0
- data/test/proj_test.rb +46 -4
- data/test/projection_test.rb +646 -222
- data/test/session_test.rb +78 -0
- data/test/transformation_test.rb +149 -7
- data/test/unit_test.rb +57 -28
- metadata +51 -13
- data/lib/api/api_4_9.rb +0 -31
- data/lib/proj/config.rb +0 -70
- data/lib/proj/point.rb +0 -72
- data/test/prime_meridians_test.rb +0 -33
data/lib/proj/pj_object.rb
CHANGED
@@ -1,80 +1,670 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
module Proj
|
3
|
-
class PjObject
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Proj
|
3
|
+
class PjObject
|
4
|
+
# @!visibility private
|
5
|
+
def self.create_object(pointer, context)
|
6
|
+
unless pointer.null?
|
7
|
+
# Get the proj type
|
8
|
+
type = Api.proj_get_type(pointer)
|
9
|
+
|
10
|
+
# If we can create a derived classes, but we do not want to call their
|
11
|
+
# initializers since we already have a valid PROJ object that we
|
12
|
+
# just have to wrap
|
13
|
+
klass = case type
|
14
|
+
when :PJ_TYPE_CRS, :PJ_TYPE_GEODETIC_CRS, :PJ_TYPE_GEOCENTRIC_CRS,
|
15
|
+
:PJ_TYPE_GEOGRAPHIC_2D_CRS, :PJ_TYPE_GEOGRAPHIC_3D_CRS,
|
16
|
+
:PJ_TYPE_GEOGRAPHIC_CRS, :PJ_TYPE_VERTICAL_CRS,:PJ_TYPE_PROJECTED_CRS,
|
17
|
+
:PJ_TYPE_COMPOUND_CRS, :PJ_TYPE_TEMPORAL_CRS, :PJ_TYPE_ENGINEERING_CRS,
|
18
|
+
:PJ_TYPE_BOUND_CRS, :PJ_TYPE_OTHER_CRS
|
19
|
+
Crs
|
20
|
+
when :PJ_TYPE_CONVERSION, :PJ_TYPE_OTHER_COORDINATE_OPERATION, :PJ_TYPE_CONCATENATED_OPERATION
|
21
|
+
Conversion
|
22
|
+
when :PJ_TYPE_TRANSFORMATION
|
23
|
+
Transformation
|
24
|
+
when :PJ_TYPE_TEMPORAL_DATUM, :PJ_TYPE_ENGINEERING_DATUM, :PJ_TYPE_PARAMETRIC_DATUM,
|
25
|
+
:PJ_TYPE_GEODETIC_REFERENCE_FRAME, :PJ_TYPE_DYNAMIC_GEODETIC_REFERENCE_FRAME,
|
26
|
+
:PJ_TYPE_VERTICAL_REFERENCE_FRAME, :PJ_TYPE_DYNAMIC_VERTICAL_REFERENCE_FRAME
|
27
|
+
Datum
|
28
|
+
when :PJ_TYPE_DATUM_ENSEMBLE
|
29
|
+
DatumEnsemble
|
30
|
+
when :PJ_TYPE_ELLIPSOID
|
31
|
+
Ellipsoid
|
32
|
+
when :PJ_TYPE_PRIME_MERIDIAN
|
33
|
+
PrimeMeridian
|
34
|
+
else
|
35
|
+
# Return whatever the current class is
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Now setup the instance variables
|
40
|
+
result = klass.allocate
|
41
|
+
result.instance_variable_set(:@pointer, pointer)
|
42
|
+
result.instance_variable_set(:@context, context)
|
43
|
+
|
44
|
+
result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Instantiates an object from a string
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# conversion = Proj::Conversion.create("+proj=helmert")
|
52
|
+
#
|
53
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_create
|
54
|
+
#
|
55
|
+
# @param value [String] Can be:
|
56
|
+
# * Proj string
|
57
|
+
# * WKT string
|
58
|
+
# * Object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", "urn:ogc:def:coordinateOperation:EPSG::1671"),
|
59
|
+
# * 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.
|
60
|
+
# * 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"),
|
61
|
+
# * OGC URN combining references for concatenated operations (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618")
|
62
|
+
# * PROJJSON string. The jsonschema is at https://proj.org/schemas/v0.4/projjson.schema.json (added in 6.2)
|
63
|
+
# * compound CRS made from two object names separated with " + ". e.g. "WGS 84 + EGM96 height" (added in 7.1)
|
64
|
+
#
|
65
|
+
# @return [PjObject] Crs or Transformation
|
66
|
+
def self.create(value, context=nil)
|
67
|
+
ptr = Api.proj_create(context || Context.current, value)
|
68
|
+
|
69
|
+
if ptr.null?
|
70
|
+
Error.check_object(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
create_object(ptr, context)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Instantiates an object from a database lookup
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)
|
80
|
+
#
|
81
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_create_from_database
|
82
|
+
#
|
83
|
+
# @param auth_name [String] Authority name (must not be nil)
|
84
|
+
# @param code [String] Object code (must not be nil)
|
85
|
+
# @param category [PJ_CATEGORY] A PJ_CATEGORY enum value
|
86
|
+
# @param use_alternative_grid_names [Boolean] Whether PROJ alternative grid names should be substituted to the official grid names. Only used on transformations. Defaults to false
|
87
|
+
# @param context [Context] Context. If nil the current context is used
|
88
|
+
#
|
89
|
+
# @return [PjObject] Crs or Transformation
|
90
|
+
def self.create_from_database(auth_name, code, category, use_alternative_grid_names = false, context = nil)
|
91
|
+
context ||= Context.current
|
92
|
+
ptr = Api.proj_create_from_database(context, auth_name, code, category,
|
93
|
+
use_alternative_grid_names ? 1 : 0, nil)
|
94
|
+
|
95
|
+
if ptr.null?
|
96
|
+
Error.check_context(context)
|
97
|
+
end
|
98
|
+
|
99
|
+
create_object(ptr, context)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Return a list of objects by their name
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# objects = Proj::PjObject.create_from_name("WGS 84", Context.current)
|
106
|
+
#
|
107
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_create_from_name
|
108
|
+
#
|
109
|
+
# @param name [String] Search value, must be at least two characters
|
110
|
+
# @param context [Context] Context. If nil the current context is used
|
111
|
+
# @param auth_name [String] Authority name or nil for all authorities. Default is nil
|
112
|
+
# @param types [Array<PJ_TYPE>] Types of objects to search for or nil for all types. Default is nil
|
113
|
+
# @param approximate_match [Boolean] Whether approximate name identification is allowed. Default is false
|
114
|
+
# @param limit [Integer] The maximum number of results to return, use 0 for all results. Default is 0
|
115
|
+
#
|
116
|
+
# @return [PjObjects] Found objects
|
117
|
+
def self.create_from_name(name, context, auth_name: nil, types: nil, approximate_match: false, limit: 0)
|
118
|
+
if types
|
119
|
+
types_ptr = FFI::MemoryPointer.new(Api::PJ_TYPE.native_type, types.size)
|
120
|
+
types_ptr.write_array_of_int(types.map { |symbol| Api::PJ_TYPE[symbol]})
|
121
|
+
types_count = types.size
|
122
|
+
else
|
123
|
+
types_ptr = nil
|
124
|
+
types_count = 0
|
125
|
+
end
|
126
|
+
|
127
|
+
ptr = Api.proj_create_from_name(context, auth_name, name, types_ptr, types_count, approximate_match ? 1 : 0, limit, nil)
|
128
|
+
PjObjects.new(ptr, context)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Instantiates an object from a WKT string.
|
132
|
+
#
|
133
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_create_from_wkt
|
134
|
+
#
|
135
|
+
# @param wkt [String] WKT string (must not be nil)
|
136
|
+
# @param context [Context] Context. If nil the current context is used
|
137
|
+
# @param strict [Boolean] Enables strict validation will be enabled. Default is false
|
138
|
+
# @param unset_identifiers [Boolean] When enabled object identifiers are unset when there is
|
139
|
+
# a contradiction between the definition from WKT and the one
|
140
|
+
# from the database. Defaults to nil because this option
|
141
|
+
# is only available in Proj 9+
|
142
|
+
#
|
143
|
+
# @return [PjObject] Crs or Transformation
|
144
|
+
def self.create_from_wkt(wkt, context = nil, strict: false, unset_identifiers: nil)
|
145
|
+
out_warnings = FFI::MemoryPointer.new(:pointer)
|
146
|
+
out_grammar_errors = FFI::MemoryPointer.new(:pointer)
|
147
|
+
|
148
|
+
# @param wkt_type [PJ_WKT_TYPE] WKT version to output. Defaults to PJ_WKT2_2018
|
149
|
+
# @param multiline [Boolean] Specifies if output span multiple lines. Defaults to true.
|
150
|
+
# @param indentation_width [Integer] Specifies the indentation level. Defaults to 4.
|
151
|
+
#
|
152
|
+
# @return [String] wkt
|
153
|
+
|
154
|
+
# Unset
|
155
|
+
options = {"STRICT": strict ? "YES" : "NO"}
|
156
|
+
case unset_identifiers
|
157
|
+
when TrueClass
|
158
|
+
options["UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF"] = "YES"
|
159
|
+
when FalseClass
|
160
|
+
options["UNSET_IDENTIFIERS_IF_INCOMPATIBLE_DEF"] = "NO"
|
161
|
+
end
|
162
|
+
options_ptr = create_options_pointer(options)
|
163
|
+
|
164
|
+
ptr = Api.proj_create_from_wkt(context, wkt, options_ptr, out_warnings, out_grammar_errors)
|
165
|
+
|
166
|
+
warnings = Strings.new(out_warnings.read_pointer)
|
167
|
+
errors = Strings.new(out_grammar_errors.read_pointer)
|
168
|
+
|
169
|
+
unless errors.empty?
|
170
|
+
raise(RuntimeError, errors.join(". "))
|
171
|
+
end
|
172
|
+
|
173
|
+
unless warnings.empty?
|
174
|
+
warn(warnings.join(". "))
|
175
|
+
end
|
176
|
+
|
177
|
+
create_object(ptr, context)
|
178
|
+
end
|
179
|
+
|
180
|
+
# @!visibility private
|
181
|
+
def self.finalize(pointer)
|
182
|
+
proc do
|
183
|
+
Api.proj_destroy(pointer)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def initialize(pointer, context=nil)
|
188
|
+
if pointer.null?
|
189
|
+
raise(Error, "Cannot create a PjObject with a null pointer")
|
190
|
+
end
|
191
|
+
@pointer = pointer
|
192
|
+
@context = context
|
193
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@pointer))
|
194
|
+
end
|
195
|
+
|
196
|
+
def initialize_copy(original)
|
197
|
+
ObjectSpace.undefine_finalizer(self)
|
198
|
+
|
199
|
+
super
|
200
|
+
|
201
|
+
@pointer = Api.proj_clone(original.context, original)
|
202
|
+
|
203
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(@pointer))
|
204
|
+
end
|
205
|
+
|
206
|
+
# Assign a new context to this object
|
207
|
+
#
|
208
|
+
# @param [Context] The context to assign to this object
|
209
|
+
def context=(value)
|
210
|
+
Api.proj_assign_context(self, value)
|
211
|
+
end
|
212
|
+
|
213
|
+
def to_ptr
|
214
|
+
@pointer
|
215
|
+
end
|
216
|
+
|
217
|
+
def context
|
218
|
+
@context || Context.current
|
219
|
+
end
|
220
|
+
|
221
|
+
def errno
|
222
|
+
Api.proj_errno(self)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Returns whether an object is deprecated
|
226
|
+
#
|
227
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_is_deprecated
|
228
|
+
#
|
229
|
+
# @return [Boolean] True if the object is deprecated, otherwise false
|
230
|
+
def deprecated?
|
231
|
+
result = Api.proj_is_deprecated(self)
|
232
|
+
result == 1 ? true : false
|
233
|
+
end
|
234
|
+
|
235
|
+
# Return whether two objects are equivalent. For versions 6.3.0 and higher
|
236
|
+
# the check may use using the proj database to check for name aliases
|
237
|
+
#
|
238
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_is_equivalent_to
|
239
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_is_equivalent_to_with_ctx
|
240
|
+
#
|
241
|
+
# @param other [PjObject] Object to compare to
|
242
|
+
# @param comparison [PJ_COMPARISON_CRITERION] Comparison criterion
|
243
|
+
#
|
244
|
+
# @return [Boolean] True if the objects are equivalent, otherwise false
|
245
|
+
def equivalent_to?(other, comparison)
|
246
|
+
result = if defined?(Api.proj_is_equivalent_to_with_ctx)
|
247
|
+
Api.proj_is_equivalent_to_with_ctx(self.context, self, other, comparison)
|
248
|
+
else
|
249
|
+
Api.proj_is_equivalent_to(self, other, comparison)
|
250
|
+
end
|
251
|
+
result == 1 ? true : false
|
252
|
+
end
|
253
|
+
|
254
|
+
# Returns the current error-state of this object
|
255
|
+
#
|
256
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_errno
|
257
|
+
#
|
258
|
+
# @return [Integer] An non-zero error codes indicates an error either with the transformation setup or during a transformation
|
259
|
+
def errorno
|
260
|
+
Api.proj_errno(self)
|
261
|
+
end
|
262
|
+
|
263
|
+
# Get information about this object
|
264
|
+
#
|
265
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
266
|
+
#
|
267
|
+
# @return [PJ_PROJ_INFO]
|
268
|
+
def info
|
269
|
+
Api.proj_pj_info(self)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Short ID of the operation the PJ object is based on, that is, what comes after the +proj=
|
273
|
+
# in a proj-string, e.g. "merc".
|
274
|
+
#
|
275
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
276
|
+
#
|
277
|
+
# @return [String]
|
278
|
+
def id
|
279
|
+
self.info[:id]
|
280
|
+
end
|
281
|
+
|
282
|
+
# Long description of the operation the PJ object is based on, e.g. "Mercator Cyl, Sph&Ell lat_ts="
|
283
|
+
#
|
284
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
285
|
+
#
|
286
|
+
# @return [String]
|
287
|
+
def description
|
288
|
+
self.info[:description] ? self.info[:description].force_encoding('UTF-8') : nil
|
289
|
+
end
|
290
|
+
|
291
|
+
# The proj-string that was used to create the PJ object with, e.g. "+proj=merc +lat_0=24 +lon_0=53 +ellps=WGS84"
|
292
|
+
#
|
293
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
294
|
+
#
|
295
|
+
# @return [String]
|
296
|
+
def definition
|
297
|
+
self.info[:definition] ? self.info[:definition].force_encoding('UTF-8') : nil
|
298
|
+
end
|
299
|
+
|
300
|
+
# Returns true if an an inverse mapping of the defined operation exists, otherwise false
|
301
|
+
#
|
302
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
303
|
+
#
|
304
|
+
# @return [Boolean]
|
305
|
+
def has_inverse?
|
306
|
+
self.info[:has_inverse] == 1 ? true : false
|
307
|
+
end
|
308
|
+
|
309
|
+
# Expected accuracy of the transformation. -1 if unknown
|
310
|
+
#
|
311
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_pj_info
|
312
|
+
#
|
313
|
+
# @return [Double]
|
314
|
+
def accuracy
|
315
|
+
self.info[:accuracy]
|
316
|
+
end
|
317
|
+
|
318
|
+
# Return the type of an object
|
319
|
+
#
|
320
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_type
|
321
|
+
#
|
322
|
+
# @return [PJ_TYPE]
|
323
|
+
def proj_type
|
324
|
+
Api.proj_get_type(self)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns the name of an object
|
328
|
+
#
|
329
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_name
|
330
|
+
#
|
331
|
+
# @return [String]
|
332
|
+
def name
|
333
|
+
Api.proj_get_name(self)&.force_encoding('UTF-8')
|
334
|
+
end
|
335
|
+
|
336
|
+
# Returns the authority name / codespace of an identifier of an object.
|
337
|
+
#
|
338
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_id_auth_name
|
339
|
+
#
|
340
|
+
# @param index [Integer] Index of the identifier. 0 is for the first identifier. Default is 0.
|
341
|
+
#
|
342
|
+
# @return [String]
|
343
|
+
def auth_name(index=0)
|
344
|
+
Api.proj_get_id_auth_name(self, index)&.force_encoding('UTF-8')
|
345
|
+
end
|
346
|
+
|
347
|
+
# Get the code of an identifier of an object
|
348
|
+
#
|
349
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_id_code
|
350
|
+
#
|
351
|
+
# @param index [Integer] Index of the identifier. 0 is the first identifier. Default is 0
|
352
|
+
#
|
353
|
+
# @return [String] The code or nil in case of error or missing name
|
354
|
+
def id_code(index=0)
|
355
|
+
Api.proj_get_id_code(self, index)
|
356
|
+
end
|
357
|
+
|
358
|
+
# Get the remarks of an object
|
359
|
+
#
|
360
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_remarks
|
361
|
+
#
|
362
|
+
# @return [String] Remarks or nil in case of error
|
363
|
+
def remarks
|
364
|
+
Api.proj_get_remarks(self)
|
365
|
+
end
|
366
|
+
|
367
|
+
# Get the scope of an object
|
368
|
+
#
|
369
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_scope
|
370
|
+
#
|
371
|
+
# @return [String] Scope or nil in case of error or a missing scope
|
372
|
+
def scope
|
373
|
+
Api.proj_get_scope(self)
|
374
|
+
end
|
375
|
+
|
376
|
+
def auth(index=0)
|
377
|
+
auth_name = self.auth_name(index)
|
378
|
+
code = self.id_code(index)
|
379
|
+
|
380
|
+
if auth_name and code
|
381
|
+
"#{self.auth_name(index)}:#{self.id_code(index)}"
|
382
|
+
elsif auth_name
|
383
|
+
auth_name
|
384
|
+
elsif code
|
385
|
+
code
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
# Return the area of use of an object
|
390
|
+
#
|
391
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_area_of_use
|
392
|
+
#
|
393
|
+
# @return [Area] In case of multiple usages, this will be the one of first usage.
|
394
|
+
def area_of_use
|
395
|
+
p_name = FFI::MemoryPointer.new(:pointer)
|
396
|
+
p_west_lon_degree = FFI::MemoryPointer.new(:double)
|
397
|
+
p_south_lat_degree = FFI::MemoryPointer.new(:double)
|
398
|
+
p_east_lon_degree = FFI::MemoryPointer.new(:double)
|
399
|
+
p_north_lat_degree = FFI::MemoryPointer.new(:double)
|
400
|
+
|
401
|
+
result = Api.proj_get_area_of_use(self.context, self,
|
402
|
+
p_west_lon_degree, p_south_lat_degree, p_east_lon_degree, p_north_lat_degree,
|
403
|
+
p_name)
|
404
|
+
if result != 1
|
405
|
+
Error.check_object(self)
|
406
|
+
end
|
407
|
+
|
408
|
+
name = p_name.read_pointer.read_string_to_null.force_encoding('utf-8')
|
409
|
+
Area.new(west_lon_degree: p_west_lon_degree.read_double,
|
410
|
+
south_lat_degree: p_south_lat_degree.read_double,
|
411
|
+
east_lon_degree: p_east_lon_degree.read_double,
|
412
|
+
north_lat_degree: p_north_lat_degree.read_double,
|
413
|
+
name: name)
|
414
|
+
end
|
415
|
+
|
416
|
+
# Return the base CRS of a BoundCRS or a DerivedCRS/ProjectedCRS, or the source CRS of a
|
417
|
+
# CoordinateOperation, or the CRS of a CoordinateMetadata.
|
418
|
+
#
|
419
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_source_crs
|
420
|
+
#
|
421
|
+
# @return [Crs]
|
422
|
+
def source_crs
|
423
|
+
ptr = Api.proj_get_source_crs(self.context, self)
|
424
|
+
self.class.create_object(ptr, self.context)
|
425
|
+
end
|
426
|
+
|
427
|
+
# Return the hub CRS of a BoundCRS or the target CRS of a CoordinateOperation
|
428
|
+
#
|
429
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_target_crs
|
430
|
+
#
|
431
|
+
# @return [Crs]
|
432
|
+
def target_crs
|
433
|
+
ptr = Api.proj_get_target_crs(self.context, self)
|
434
|
+
self.class.create_object(ptr, self.context)
|
435
|
+
end
|
436
|
+
|
437
|
+
# Calculate various cartographic properties, such as scale factors, angular distortion and
|
438
|
+
# meridian convergence. Depending on the underlying projection values will be
|
439
|
+
# calculated either numerically (default) or analytically. The function also calculates
|
440
|
+
# the partial derivatives of the given coordinate.
|
441
|
+
#
|
442
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_factors
|
443
|
+
#
|
444
|
+
# @param coordinate [Coordinate] Input geodetic coordinate in radians
|
445
|
+
#
|
446
|
+
# @return [PJ_FACTORS]
|
447
|
+
def factors(coordinate)
|
448
|
+
Api.proj_factors(self, coordinate)
|
449
|
+
end
|
450
|
+
|
451
|
+
# Return a list of non-deprecated objects related to the passed one
|
452
|
+
#
|
453
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_non_deprecated
|
454
|
+
#
|
455
|
+
# @return [Array] Array of objects
|
456
|
+
def non_deprecated
|
457
|
+
ptr = Api.proj_get_non_deprecated(self.context, self)
|
458
|
+
PjObjects.new(ptr, self.context)
|
459
|
+
end
|
460
|
+
|
461
|
+
# Calculate geodesic distance between two points in geodetic coordinates. The calculated distance is between
|
462
|
+
# the two points located on the ellipsoid. Note that the axis order of the transformation object
|
463
|
+
# is not taken into account, so even though a CRS object comes with axis ordering
|
464
|
+
# latitude/longitude coordinates used in this function should be reordered as longitude/latitude.
|
465
|
+
#
|
466
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_lp_dist
|
467
|
+
#
|
468
|
+
# @param coord1 [Coordinate] Coordinate of first point. Must be lat/long in radians
|
469
|
+
# @param coord2 [Coordinate] Coordinate of second point. Must be lat/long in radians
|
470
|
+
#
|
471
|
+
# @return [Double] Distance between the coordinates in meters
|
472
|
+
def lp_distance(coord1, coord2)
|
473
|
+
Api.proj_lp_dist(self, coord1, coord2)
|
474
|
+
end
|
475
|
+
|
476
|
+
# Calculate geodesic distance between two points in geodetic coordinates. Similar to
|
477
|
+
# PjObject#lp_distance but also takes the height above the ellipsoid into account.
|
478
|
+
#
|
479
|
+
# Note that the axis order of the transformation object is not taken into account, so even though
|
480
|
+
# a CRS object comes with axis ordering latitude/longitude coordinates used in this function
|
481
|
+
# should be reordered as longitude/latitude.
|
482
|
+
#
|
483
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_lpz_dist
|
484
|
+
#
|
485
|
+
# @param coord1 [Coordinate] Coordinate of first point. Must be lat/long in radians
|
486
|
+
# @param coord2 [Coordinate] Coordinate of second point. Must be lat/long in radians
|
487
|
+
#
|
488
|
+
# @return [Double] Distance between the coordinates in meters
|
489
|
+
def lpz_distance(coord1, coord2)
|
490
|
+
Api.proj_lpz_dist(self, coord1, coord2)
|
491
|
+
end
|
492
|
+
|
493
|
+
# Calculate the 2-dimensional euclidean between two projected coordinates
|
494
|
+
#
|
495
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_xy_dist
|
496
|
+
#
|
497
|
+
# @param coord1 [Coordinate] Coordinate of first point
|
498
|
+
# @param coord2 [Coordinate] Coordinate of second point
|
499
|
+
#
|
500
|
+
# @return [Double] Distance between the coordinates in meters
|
501
|
+
def xy_distance(coord1, coord2)
|
502
|
+
Api.proj_xy_dist(coord1, coord2)
|
503
|
+
end
|
504
|
+
|
505
|
+
# Calculate the 2-dimensional euclidean between two projected coordinates. Similar to
|
506
|
+
# PjObject#xy_distance but also takes height into account.
|
507
|
+
#
|
508
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_xyz_dist
|
509
|
+
#
|
510
|
+
# @param coord1 [Coordinate] Coordinate of first point
|
511
|
+
# @param coord2 [Coordinate] Coordinate of second point
|
512
|
+
#
|
513
|
+
# @return [Double] Distance between the coordinates in meters
|
514
|
+
def xyz_distance(coord1, coord2)
|
515
|
+
Api.proj_xyz_dist(coord1, coord2)
|
516
|
+
end
|
517
|
+
|
518
|
+
# Calculate the geodesic distance as well as forward and reverse azimuth between two points on the ellipsoid.
|
519
|
+
#
|
520
|
+
# Note that the axis order of the transformation object is not taken into account, so even though
|
521
|
+
# a CRS object comes with axis ordering latitude/longitude coordinates used in this function
|
522
|
+
# should be reordered as longitude/latitude.
|
523
|
+
#
|
524
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_geod
|
525
|
+
#
|
526
|
+
# @param coord1 [Coordinate] Coordinate of first point. Must be lat/long in radians
|
527
|
+
# @param coord2 [Coordinate] Coordinate of first point. Must be lat/long in radians
|
528
|
+
#
|
529
|
+
# @return [Coordinate] The first value is the distance between coord1 and coord2 in meters,
|
530
|
+
# the second is the forward azimuth, the third value the reverse azimuth and the fourth value is unused.
|
531
|
+
def geod_distance(coord1, coord2)
|
532
|
+
ptr = Api.proj_geod(self, coord1, coord2)
|
533
|
+
Coordinate.from_coord(ptr)
|
534
|
+
end
|
535
|
+
|
536
|
+
# Returns if an operation expects input in radians
|
537
|
+
#
|
538
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_angular_input
|
539
|
+
#
|
540
|
+
# @param direction []PJ_DIRECTION] Direction of transformation
|
541
|
+
def angular_input?(direction)
|
542
|
+
result = Api.proj_angular_input(self, direction)
|
543
|
+
result == 1 ? true : false
|
544
|
+
end
|
545
|
+
|
546
|
+
# Check if an operation returns output in radians
|
547
|
+
#
|
548
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_angular_output
|
549
|
+
#
|
550
|
+
# @param direction []PJ_DIRECTION] Direction of transformation
|
551
|
+
def angular_output?(direction)
|
552
|
+
result = Api.proj_angular_output(self, direction)
|
553
|
+
result == 1 ? true : false
|
554
|
+
end
|
555
|
+
|
556
|
+
# Returns if an operation expects input in degrees
|
557
|
+
#
|
558
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_degree_input
|
559
|
+
#
|
560
|
+
# @param direction []PJ_DIRECTION] Direction of transformation
|
561
|
+
def degree_input?(direction)
|
562
|
+
result = Api.proj_degree_input(self, direction)
|
563
|
+
result == 1 ? true : false
|
564
|
+
end
|
565
|
+
|
566
|
+
# Check if an operation returns output in degrees
|
567
|
+
#
|
568
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_degree_output
|
569
|
+
#
|
570
|
+
# @param direction []PJ_DIRECTION] Direction of transformation
|
571
|
+
def degree_output?(direction)
|
572
|
+
result = Api.proj_degree_output(self, direction)
|
573
|
+
result == 1 ? true : false
|
574
|
+
end
|
575
|
+
|
576
|
+
# Returns the proj representation string for this object
|
577
|
+
#
|
578
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_as_proj_string
|
579
|
+
#
|
580
|
+
# @param proj_version [PJ_PROJ_STRING_TYPE] The proj version. Defaults to :PJ_PROJ_5
|
581
|
+
# @param use_approx_tmerc [Boolean] True adds the +approx flag to +proj=tmerc or +proj=utm. Defaults to false
|
582
|
+
# @param multiline [Boolean] Specifies if output span multiple lines. Defaults to false.
|
583
|
+
# @param indentation_width [Integer] Specifies the indentation level. Defaults to 2.
|
584
|
+
# @param max_line_length [Integer] Specifies the max line length level. Defaults to 80.
|
585
|
+
#
|
586
|
+
# @return [String]
|
587
|
+
def to_proj_string(proj_version=:PJ_PROJ_5, use_approx_tmerc: false, multiline: false,
|
588
|
+
indentation_width: 2, max_line_length: 80)
|
589
|
+
|
590
|
+
options = {"USE_APPROX_TMERC": use_approx_tmerc ? "YES" : "NO",
|
591
|
+
"MULTILINE": multiline ? "YES" : "NO",
|
592
|
+
"INDENTATION_WIDTH": indentation_width,
|
593
|
+
"MAX_LINE_LENGTH": max_line_length}
|
594
|
+
|
595
|
+
options_ptr = create_options_pointer(options)
|
596
|
+
Api.proj_as_proj_string(self.context, self, proj_version, options_ptr).force_encoding('UTF-8')
|
597
|
+
end
|
598
|
+
|
599
|
+
# Returns the json representation for this object
|
600
|
+
#
|
601
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_as_projjson
|
602
|
+
#
|
603
|
+
# @param multiline [Boolean] Specifies if output span multiple lines. Defaults to true.
|
604
|
+
# @param indentation_width [Integer] Specifies the indentation level. Defaults to 2.
|
605
|
+
#
|
606
|
+
# @return [String]
|
607
|
+
def to_json(multiline: true, indentation_width: 2)
|
608
|
+
options = {"MULTILINE": multiline ? "YES" : "NO",
|
609
|
+
"INDENTATION_WIDTH": indentation_width}
|
610
|
+
|
611
|
+
options_ptr = create_options_pointer(options)
|
612
|
+
Api.proj_as_projjson(self.context, self, options_ptr).force_encoding('UTF-8')
|
613
|
+
end
|
614
|
+
|
615
|
+
# Returns the wkt representation for this object
|
616
|
+
#
|
617
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_as_wkt
|
618
|
+
#
|
619
|
+
# @param wkt_type [PJ_WKT_TYPE] WKT version to output. Defaults to PJ_WKT2_2018
|
620
|
+
# @param multiline [Boolean] Specifies if output span multiple lines. Defaults to true.
|
621
|
+
# @param indentation_width [Integer] Specifies the indentation level. Defaults to 4.
|
622
|
+
#
|
623
|
+
# @return [String] wkt
|
624
|
+
def to_wkt(wkt_type=:PJ_WKT2_2019, multiline: true, indentation_width: 4)
|
625
|
+
options = {"MULTILINE": multiline ? "YES" : "NO",
|
626
|
+
"INDENTATION_WIDTH": indentation_width,
|
627
|
+
"OUTPUT_AXIS": "AUTO",
|
628
|
+
"STRICT": "YES",
|
629
|
+
"ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS": "NO"}
|
630
|
+
|
631
|
+
options_ptr = create_options_pointer(options)
|
632
|
+
result = Api.proj_as_wkt(self.context, self, wkt_type, nil)
|
633
|
+
|
634
|
+
if result.nil?
|
635
|
+
Error.check_object(self)
|
636
|
+
end
|
637
|
+
|
638
|
+
result.force_encoding('UTF-8')
|
639
|
+
end
|
640
|
+
|
641
|
+
# Returns the string representation for this object
|
642
|
+
#
|
643
|
+
# @return [String] String
|
644
|
+
def to_s
|
645
|
+
"#<#{self.class.name} - #{name}, #{proj_type}>"
|
646
|
+
end
|
647
|
+
|
648
|
+
private
|
649
|
+
|
650
|
+
def self.create_options_pointer(options)
|
651
|
+
options = options.compact
|
652
|
+
options_ptr_array = options.map do |key, value|
|
653
|
+
FFI::MemoryPointer.from_string("#{key}=#{value}")
|
654
|
+
end
|
655
|
+
|
656
|
+
if options_ptr_array.empty?
|
657
|
+
nil
|
658
|
+
else
|
659
|
+
# Add extra item at end for null pointer
|
660
|
+
options_ptr = FFI::MemoryPointer.new(:pointer, options.size + 1)
|
661
|
+
options_ptr.write_array_of_pointer(options_ptr_array)
|
662
|
+
options_ptr
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
def create_options_pointer(options)
|
667
|
+
self.class.create_options_pointer(options)
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|