proj4rb 4.1.0 → 5.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.md +98 -0
- data/Gemfile +4 -4
- data/README.md +53 -0
- data/lib/api/proj.rb +750 -0
- data/lib/api/proj_experimental.rb +7 -0
- data/lib/api/proj_ffi.rb +47 -0
- data/lib/api/proj_version.rb +26 -0
- data/lib/examples/axis_order_normalization.rb +13 -0
- data/lib/examples/batch_transformation.rb +25 -0
- data/lib/examples/context_logging.rb +26 -0
- data/lib/examples/crs_identification.rb +18 -0
- data/lib/examples/database_query.rb +27 -0
- data/lib/examples/geodetic_distance.rb +38 -0
- data/lib/examples/geodetic_to_projected.rb +18 -0
- data/lib/examples/operation_factory_context.rb +19 -0
- data/lib/examples/pipeline_operator.rb +21 -0
- data/lib/examples/promote_demote_3d.rb +23 -0
- data/lib/examples/serialization_formats.rb +17 -0
- data/lib/examples/transform_bounds.rb +18 -0
- data/lib/examples/transformation_with_area.rb +18 -0
- data/lib/proj/area.rb +74 -74
- data/lib/proj/axis_info.rb +44 -44
- data/lib/proj/bounds.rb +22 -0
- data/lib/proj/bounds3d.rb +45 -0
- data/lib/proj/context.rb +57 -23
- data/lib/proj/conversion.rb +94 -91
- data/lib/proj/coordinate.rb +304 -281
- data/lib/proj/coordinate_metadata.rb +38 -0
- data/lib/proj/coordinate_operation_mixin.rb +464 -381
- data/lib/proj/coordinate_system.rb +143 -137
- data/lib/proj/crs.rb +688 -672
- data/lib/proj/crs_info.rb +47 -47
- data/lib/proj/database.rb +310 -305
- data/lib/proj/datum.rb +32 -32
- data/lib/proj/datum_ensemble.rb +34 -34
- data/lib/proj/domain.rb +82 -0
- data/lib/proj/ellipsoid.rb +77 -77
- data/lib/proj/error.rb +7 -8
- data/lib/proj/file_api_callbacks.rb +165 -0
- data/lib/proj/grid.rb +121 -121
- data/lib/proj/grid_cache.rb +65 -64
- data/lib/proj/grid_info.rb +19 -19
- data/lib/proj/life_span.rb +21 -0
- data/lib/proj/network_api_callbacks.rb +86 -0
- data/lib/proj/operation.rb +66 -42
- data/lib/proj/operation_factory_context.rb +4 -2
- data/lib/proj/options.rb +41 -0
- data/lib/proj/parameter.rb +37 -37
- data/lib/proj/parameters.rb +106 -107
- data/lib/proj/pj_axis_description.rb +26 -0
- data/lib/proj/pj_object.rb +602 -670
- data/lib/proj/pj_objects.rb +45 -45
- data/lib/proj/pj_param_description.rb +28 -0
- data/lib/proj/prime_meridian.rb +65 -65
- data/lib/proj/projection.rb +1771 -698
- data/lib/proj/session.rb +2 -0
- data/lib/proj/transformation.rb +102 -102
- data/lib/proj/unit.rb +81 -108
- data/lib/proj.rb +10 -3
- data/lib/proj4.rb +5 -5
- data/proj4rb.gemspec +10 -5
- data/test/abstract_test.rb +7 -28
- data/test/context_test.rb +210 -172
- data/test/context_validation_test.rb +11 -0
- data/test/conversion_test.rb +376 -368
- data/test/coordinate_metadata_test.rb +34 -0
- data/test/coordinate_system_test.rb +162 -144
- data/test/coordinate_test.rb +289 -34
- data/test/crs_test.rb +1112 -1072
- data/test/database_test.rb +407 -359
- data/test/datum_ensemble_test.rb +64 -64
- data/test/datum_test.rb +61 -54
- data/test/domain_test.rb +72 -0
- data/test/ellipsoid_test.rb +80 -80
- data/test/examples_test.rb +149 -0
- data/test/file_api_example.rb +58 -0
- data/test/file_api_test.rb +74 -66
- data/test/grid_cache_test.rb +72 -72
- data/test/grid_test.rb +126 -141
- data/test/network_api_example.rb +48 -0
- data/test/network_api_test.rb +33 -45
- data/test/operation_factory_context_test.rb +225 -201
- data/test/operation_test.rb +40 -29
- data/test/options_test.rb +17 -0
- data/test/parameters_test.rb +86 -40
- data/test/pj_object_test.rb +221 -179
- data/test/prime_meridian_test.rb +75 -75
- data/test/proj_test.rb +58 -58
- data/test/projection_test.rb +680 -650
- data/test/session_test.rb +78 -77
- data/test/transformation_test.rb +238 -210
- data/test/unit_test.rb +114 -76
- metadata +45 -31
- data/ChangeLog +0 -89
- data/README.rdoc +0 -207
- data/lib/api/api.rb +0 -117
- data/lib/api/api_5_0.rb +0 -338
- data/lib/api/api_5_1.rb +0 -7
- data/lib/api/api_5_2.rb +0 -5
- data/lib/api/api_6_0.rb +0 -146
- data/lib/api/api_6_1.rb +0 -5
- data/lib/api/api_6_2.rb +0 -10
- data/lib/api/api_6_3.rb +0 -6
- data/lib/api/api_7_0.rb +0 -69
- data/lib/api/api_7_1.rb +0 -73
- data/lib/api/api_7_2.rb +0 -14
- data/lib/api/api_8_0.rb +0 -6
- data/lib/api/api_8_1.rb +0 -24
- data/lib/api/api_8_2.rb +0 -6
- data/lib/api/api_9_1.rb +0 -7
- data/lib/api/api_9_2.rb +0 -9
- data/lib/api/api_experimental.rb +0 -201
- data/lib/proj/file_api.rb +0 -166
- data/lib/proj/network_api.rb +0 -92
data/lib/proj/datum.rb
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
module Proj
|
|
2
|
-
class Datum < PjObject
|
|
3
|
-
# Returns the frame reference epoch of a dynamic geodetic or vertical reference frame
|
|
4
|
-
#
|
|
5
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_dynamic_datum_get_frame_reference_epoch
|
|
6
|
-
#
|
|
7
|
-
# @return [Float] The frame reference epoch as decimal year, or -1 in case of error.
|
|
8
|
-
def frame_reference_epoch
|
|
9
|
-
Api.proj_dynamic_datum_get_frame_reference_epoch(self.context, self)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Return the ellipsoid
|
|
13
|
-
#
|
|
14
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_get_ellipsoid
|
|
15
|
-
#
|
|
16
|
-
# @return [PjObject]
|
|
17
|
-
def ellipsoid
|
|
18
|
-
ptr = Api.proj_get_ellipsoid(self.context, self)
|
|
19
|
-
self.class.create_object(ptr, self.context)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Returns the prime meridian
|
|
23
|
-
#
|
|
24
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_get_prime_meridian
|
|
25
|
-
#
|
|
26
|
-
# @return [PjObject]
|
|
27
|
-
def prime_meridian
|
|
28
|
-
ptr = Api.proj_get_prime_meridian(self.context, self)
|
|
29
|
-
self.class.create_object(ptr, self.context)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
1
|
+
module Proj
|
|
2
|
+
class Datum < PjObject
|
|
3
|
+
# Returns the frame reference epoch of a dynamic geodetic or vertical reference frame
|
|
4
|
+
#
|
|
5
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_dynamic_datum_get_frame_reference_epoch
|
|
6
|
+
#
|
|
7
|
+
# @return [Float] The frame reference epoch as decimal year, or -1 in case of error.
|
|
8
|
+
def frame_reference_epoch
|
|
9
|
+
Api.proj_dynamic_datum_get_frame_reference_epoch(self.context, self)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Return the ellipsoid
|
|
13
|
+
#
|
|
14
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_ellipsoid
|
|
15
|
+
#
|
|
16
|
+
# @return [PjObject]
|
|
17
|
+
def ellipsoid
|
|
18
|
+
ptr = Api.proj_get_ellipsoid(self.context, self)
|
|
19
|
+
self.class.create_object(ptr, self.context)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the prime meridian
|
|
23
|
+
#
|
|
24
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_prime_meridian
|
|
25
|
+
#
|
|
26
|
+
# @return [PjObject]
|
|
27
|
+
def prime_meridian
|
|
28
|
+
ptr = Api.proj_get_prime_meridian(self.context, self)
|
|
29
|
+
self.class.create_object(ptr, self.context)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/proj/datum_ensemble.rb
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
module Proj
|
|
2
|
-
class DatumEnsemble < PjObject
|
|
3
|
-
|
|
4
|
-
# Returns the number of members of a datum ensemble
|
|
5
|
-
#
|
|
6
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member_count
|
|
7
|
-
#
|
|
8
|
-
# @return [Integer]
|
|
9
|
-
def count
|
|
10
|
-
Api.proj_datum_ensemble_get_member_count(self.context, self)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Returns a member from a datum ensemble.
|
|
14
|
-
#
|
|
15
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member
|
|
16
|
-
#
|
|
17
|
-
# @param index [Integer] Index of the datum member to extract. Should be between 0 and DatumEnsembel#count - 1.
|
|
18
|
-
#
|
|
19
|
-
# @return [Integer]
|
|
20
|
-
def [](index)
|
|
21
|
-
ptr = Api.proj_datum_ensemble_get_member(self.context, self, index)
|
|
22
|
-
self.class.create_object(ptr, self.context)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Returns the positional accuracy of the datum ensemble
|
|
26
|
-
#
|
|
27
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_accuracy
|
|
28
|
-
#
|
|
29
|
-
# @return [Float] The data ensemble accuracy or -1 in case of error
|
|
30
|
-
def accuracy
|
|
31
|
-
Api.proj_datum_ensemble_get_accuracy(self.context, self)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
1
|
+
module Proj
|
|
2
|
+
class DatumEnsemble < PjObject
|
|
3
|
+
|
|
4
|
+
# Returns the number of members of a datum ensemble
|
|
5
|
+
#
|
|
6
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member_count
|
|
7
|
+
#
|
|
8
|
+
# @return [Integer]
|
|
9
|
+
def count
|
|
10
|
+
Api.proj_datum_ensemble_get_member_count(self.context, self)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns a member from a datum ensemble.
|
|
14
|
+
#
|
|
15
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member
|
|
16
|
+
#
|
|
17
|
+
# @param index [Integer] Index of the datum member to extract. Should be between 0 and DatumEnsembel#count - 1.
|
|
18
|
+
#
|
|
19
|
+
# @return [Integer]
|
|
20
|
+
def [](index)
|
|
21
|
+
ptr = Api.proj_datum_ensemble_get_member(self.context, self, index)
|
|
22
|
+
self.class.create_object(ptr, self.context)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns the positional accuracy of the datum ensemble
|
|
26
|
+
#
|
|
27
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_accuracy
|
|
28
|
+
#
|
|
29
|
+
# @return [Float] The data ensemble accuracy or -1 in case of error
|
|
30
|
+
def accuracy
|
|
31
|
+
Api.proj_datum_ensemble_get_accuracy(self.context, self)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/proj/domain.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module Proj
|
|
4
|
+
# Represents a usage domain of a PjObject. Each domain has a scope
|
|
5
|
+
# describing the purpose and a geographic area of use.
|
|
6
|
+
# Objects can have multiple domains.
|
|
7
|
+
class Domain
|
|
8
|
+
# @return [String] The scope of this domain
|
|
9
|
+
attr_reader :scope
|
|
10
|
+
|
|
11
|
+
# @return [Area] The geographic area of use for this domain
|
|
12
|
+
attr_reader :area_of_use
|
|
13
|
+
|
|
14
|
+
# @param scope [String] The scope describing the purpose of this domain
|
|
15
|
+
# @param area_of_use [Area] The geographic area of use
|
|
16
|
+
def initialize(scope:, area_of_use:)
|
|
17
|
+
@scope = scope
|
|
18
|
+
@area_of_use = area_of_use
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns the number of usage domains for an object.
|
|
22
|
+
# Requires PROJ 9.2+. Returns 1 on older versions for backward compatibility.
|
|
23
|
+
#
|
|
24
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_domain_count
|
|
25
|
+
#
|
|
26
|
+
# @param pj_object [PjObject] The object to query
|
|
27
|
+
#
|
|
28
|
+
# @return [Integer]
|
|
29
|
+
def self.count(pj_object)
|
|
30
|
+
if Api.method_defined?(:proj_get_domain_count)
|
|
31
|
+
Api.proj_get_domain_count(pj_object)
|
|
32
|
+
else
|
|
33
|
+
1
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns all usage domains for an object.
|
|
38
|
+
# On PROJ < 9.2, falls back to {Api.proj_get_scope} and {Api.proj_get_area_of_use}
|
|
39
|
+
# and returns a single domain.
|
|
40
|
+
#
|
|
41
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_scope_ex
|
|
42
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_get_area_of_use_ex
|
|
43
|
+
#
|
|
44
|
+
# @param pj_object [PjObject] The object to query
|
|
45
|
+
#
|
|
46
|
+
# @return [Array<Domain>]
|
|
47
|
+
def self.domains(pj_object)
|
|
48
|
+
use_ex = Api.method_defined?(:proj_get_domain_count)
|
|
49
|
+
domain_count = use_ex ? Api.proj_get_domain_count(pj_object) : 1
|
|
50
|
+
|
|
51
|
+
domain_count.times.map do |index|
|
|
52
|
+
scope = use_ex ? Api.proj_get_scope_ex(pj_object, index) : Api.proj_get_scope(pj_object)
|
|
53
|
+
|
|
54
|
+
p_name = FFI::MemoryPointer.new(:pointer)
|
|
55
|
+
p_west = FFI::MemoryPointer.new(:double)
|
|
56
|
+
p_south = FFI::MemoryPointer.new(:double)
|
|
57
|
+
p_east = FFI::MemoryPointer.new(:double)
|
|
58
|
+
p_north = FFI::MemoryPointer.new(:double)
|
|
59
|
+
|
|
60
|
+
if use_ex
|
|
61
|
+
result = Api.proj_get_area_of_use_ex(pj_object.context, pj_object, index,
|
|
62
|
+
p_west, p_south, p_east, p_north, p_name)
|
|
63
|
+
else
|
|
64
|
+
result = Api.proj_get_area_of_use(pj_object.context, pj_object,
|
|
65
|
+
p_west, p_south, p_east, p_north, p_name)
|
|
66
|
+
end
|
|
67
|
+
unless result
|
|
68
|
+
Error.check_object(pj_object)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
name = p_name.read_pointer.read_string_to_null.force_encoding('utf-8')
|
|
72
|
+
area = Area.new(west_lon_degree: p_west.read_double,
|
|
73
|
+
south_lat_degree: p_south.read_double,
|
|
74
|
+
east_lon_degree: p_east.read_double,
|
|
75
|
+
north_lat_degree: p_north.read_double,
|
|
76
|
+
name: name)
|
|
77
|
+
|
|
78
|
+
new(scope: scope, area_of_use: area)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/proj/ellipsoid.rb
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
module Proj
|
|
2
|
-
class Ellipsoid < PjObject
|
|
3
|
-
# Returns a list of ellipsoids that are built into Proj. A more comprehensive
|
|
4
|
-
# list is stored in the Proj database and can be queried via PjObject#create_from_database
|
|
5
|
-
def self.built_in
|
|
6
|
-
pointer_to_array = FFI::Pointer.new(Api::
|
|
7
|
-
|
|
8
|
-
result = Array.new
|
|
9
|
-
0.step do |i|
|
|
10
|
-
pj_ellps = Api::
|
|
11
|
-
break result if pj_ellps[:id].nil?
|
|
12
|
-
result << pj_ellps
|
|
13
|
-
end
|
|
14
|
-
result
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Returns ellipsoid parameters
|
|
18
|
-
#
|
|
19
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
20
|
-
#
|
|
21
|
-
# @return [Hash] Hash of ellipsoid parameters. Axes are in meters
|
|
22
|
-
def parameters
|
|
23
|
-
@parameters ||= begin
|
|
24
|
-
out_semi_major_metre = FFI::MemoryPointer.new(:double)
|
|
25
|
-
out_semi_minor_metre = FFI::MemoryPointer.new(:double)
|
|
26
|
-
out_is_semi_minor_computed = FFI::MemoryPointer.new(:int)
|
|
27
|
-
out_inv_flattening = FFI::MemoryPointer.new(:double)
|
|
28
|
-
|
|
29
|
-
result = Api.proj_ellipsoid_get_parameters(self.context, self, out_semi_major_metre, out_semi_minor_metre, out_is_semi_minor_computed, out_inv_flattening)
|
|
30
|
-
|
|
31
|
-
if result != 1
|
|
32
|
-
Error.check_object(self)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
{semi_major_axis: out_semi_major_metre.read_double,
|
|
36
|
-
semi_minor_axis: out_semi_minor_metre.read_double,
|
|
37
|
-
semi_minor_axis_computed: out_is_semi_minor_computed.read_int == 1 ? true : false,
|
|
38
|
-
inverse_flattening: out_inv_flattening.null? ? nil : out_inv_flattening.read_double}
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Returns the semi-major axis in meters
|
|
43
|
-
#
|
|
44
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
45
|
-
#
|
|
46
|
-
# @return [Float]
|
|
47
|
-
def semi_major_axis
|
|
48
|
-
self.parameters[:semi_major_axis]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Returns the semi-minor axis in meters
|
|
52
|
-
#
|
|
53
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
54
|
-
#
|
|
55
|
-
# @return [Float]
|
|
56
|
-
def semi_minor_axis
|
|
57
|
-
self.parameters[:semi_minor_axis]
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Returns whether the semi-minor axis is computed
|
|
61
|
-
#
|
|
62
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
63
|
-
#
|
|
64
|
-
# @return [Boolean]
|
|
65
|
-
def semi_minor_axis_computed
|
|
66
|
-
self.parameters[:semi_minor_axis_computed]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Returns the inverse flattening value
|
|
70
|
-
#
|
|
71
|
-
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
72
|
-
#
|
|
73
|
-
# @return [Float]
|
|
74
|
-
def inverse_flattening
|
|
75
|
-
self.parameters[:inverse_flattening]
|
|
76
|
-
end
|
|
77
|
-
end
|
|
1
|
+
module Proj
|
|
2
|
+
class Ellipsoid < PjObject
|
|
3
|
+
# Returns a list of ellipsoids that are built into Proj. A more comprehensive
|
|
4
|
+
# list is stored in the Proj database and can be queried via PjObject#create_from_database
|
|
5
|
+
def self.built_in
|
|
6
|
+
pointer_to_array = FFI::Pointer.new(Api::PjEllps, Api.proj_list_ellps)
|
|
7
|
+
|
|
8
|
+
result = Array.new
|
|
9
|
+
0.step do |i|
|
|
10
|
+
pj_ellps = Api::PjEllps.new(pointer_to_array[i])
|
|
11
|
+
break result if pj_ellps[:id].nil?
|
|
12
|
+
result << pj_ellps
|
|
13
|
+
end
|
|
14
|
+
result
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns ellipsoid parameters
|
|
18
|
+
#
|
|
19
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
20
|
+
#
|
|
21
|
+
# @return [Hash] Hash of ellipsoid parameters. Axes are in meters
|
|
22
|
+
def parameters
|
|
23
|
+
@parameters ||= begin
|
|
24
|
+
out_semi_major_metre = FFI::MemoryPointer.new(:double)
|
|
25
|
+
out_semi_minor_metre = FFI::MemoryPointer.new(:double)
|
|
26
|
+
out_is_semi_minor_computed = FFI::MemoryPointer.new(:int)
|
|
27
|
+
out_inv_flattening = FFI::MemoryPointer.new(:double)
|
|
28
|
+
|
|
29
|
+
result = Api.proj_ellipsoid_get_parameters(self.context, self, out_semi_major_metre, out_semi_minor_metre, out_is_semi_minor_computed, out_inv_flattening)
|
|
30
|
+
|
|
31
|
+
if result != 1
|
|
32
|
+
Error.check_object(self)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
{semi_major_axis: out_semi_major_metre.read_double,
|
|
36
|
+
semi_minor_axis: out_semi_minor_metre.read_double,
|
|
37
|
+
semi_minor_axis_computed: out_is_semi_minor_computed.read_int == 1 ? true : false,
|
|
38
|
+
inverse_flattening: out_inv_flattening.null? ? nil : out_inv_flattening.read_double}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns the semi-major axis in meters
|
|
43
|
+
#
|
|
44
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
45
|
+
#
|
|
46
|
+
# @return [Float]
|
|
47
|
+
def semi_major_axis
|
|
48
|
+
self.parameters[:semi_major_axis]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns the semi-minor axis in meters
|
|
52
|
+
#
|
|
53
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
54
|
+
#
|
|
55
|
+
# @return [Float]
|
|
56
|
+
def semi_minor_axis
|
|
57
|
+
self.parameters[:semi_minor_axis]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns whether the semi-minor axis is computed
|
|
61
|
+
#
|
|
62
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
63
|
+
#
|
|
64
|
+
# @return [Boolean]
|
|
65
|
+
def semi_minor_axis_computed
|
|
66
|
+
self.parameters[:semi_minor_axis_computed]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns the inverse flattening value
|
|
70
|
+
#
|
|
71
|
+
# @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
|
|
72
|
+
#
|
|
73
|
+
# @return [Float]
|
|
74
|
+
def inverse_flattening
|
|
75
|
+
self.parameters[:inverse_flattening]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
78
|
end
|
data/lib/proj/error.rb
CHANGED
|
@@ -25,11 +25,16 @@ module Proj
|
|
|
25
25
|
PROJ_ERR_OTHER_NO_INVERSE_OP = PROJ_ERR_OTHER + 2 # No inverse method available
|
|
26
26
|
PROJ_ERR_OTHER_NETWORK_ERROR = PROJ_ERR_OTHER + 3 # Failure when accessing a network resource
|
|
27
27
|
|
|
28
|
+
def self.validate_context!(context)
|
|
29
|
+
return if context.is_a?(Context)
|
|
30
|
+
|
|
31
|
+
raise(TypeError, "expected Proj::Context, got #{context.class}")
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
# Check the context to see if an error occurred. If an error has happened will
|
|
29
35
|
# raise an exception.
|
|
30
36
|
def self.check_context(context)
|
|
31
37
|
unless context.errno == 0
|
|
32
|
-
# raise(self, "#{self.category(context.errno)}: #{self.message(context)}")
|
|
33
38
|
raise(self, self.message(context, context.errno))
|
|
34
39
|
end
|
|
35
40
|
end
|
|
@@ -61,11 +66,5 @@ module Proj
|
|
|
61
66
|
end
|
|
62
67
|
end
|
|
63
68
|
|
|
64
|
-
# Converts an errno to a error category
|
|
65
|
-
def self.category(errno)
|
|
66
|
-
self.constants.find do |constant|
|
|
67
|
-
self.const_get(constant) == errno
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
69
|
end
|
|
71
|
-
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
module Proj
|
|
2
|
+
# Include this module in a class to create a custom file API for PROJ.
|
|
3
|
+
# Install it via {Context#set_file_api}.
|
|
4
|
+
#
|
|
5
|
+
# The including class must call {#install_callbacks} in its initializer and
|
|
6
|
+
# implement the following methods:
|
|
7
|
+
#
|
|
8
|
+
# * +open(path, access_mode)+ - Open a file. +access_mode+ is one of
|
|
9
|
+
# +:PROJ_OPEN_ACCESS_READ_ONLY+, +:PROJ_OPEN_ACCESS_READ_UPDATE+, or
|
|
10
|
+
# +:PROJ_OPEN_ACCESS_CREATE+. Return a file object (any Ruby object) or nil on error.
|
|
11
|
+
# * +read(file, size_bytes)+ - Read up to +size_bytes+ from +file+, return a String.
|
|
12
|
+
# * +write(file, data)+ - Write +data+ to +file+, return the number of bytes written.
|
|
13
|
+
# * +seek(file, offset, whence)+ - Seek within +file+ using SEEK_SET/SEEK_CUR/SEEK_END.
|
|
14
|
+
# * +tell(file)+ - Return the current position in +file+.
|
|
15
|
+
# * +close(file)+ - Close +file+.
|
|
16
|
+
# * +exists(path)+ - Return true if the file at +path+ exists.
|
|
17
|
+
# * +mkdir(path)+ - Create directory at +path+, return true on success.
|
|
18
|
+
# * +unlink(path)+ - Remove file at +path+, return true on success.
|
|
19
|
+
# * +rename(original_path, new_path)+ - Rename a file, return true on success.
|
|
20
|
+
#
|
|
21
|
+
# The +file+ parameter passed to read/write/seek/tell/close is whatever object
|
|
22
|
+
# your +open+ method returned.
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# class MyFileApi
|
|
26
|
+
# include Proj::FileApiCallbacks
|
|
27
|
+
#
|
|
28
|
+
# def initialize(context)
|
|
29
|
+
# install_callbacks(context)
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# def open(path, access_mode)
|
|
33
|
+
# # return a file object or nil
|
|
34
|
+
# end
|
|
35
|
+
# # ... implement remaining methods ...
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# context.set_file_api(MyFileApi)
|
|
39
|
+
module FileApiCallbacks
|
|
40
|
+
def install_callbacks(context)
|
|
41
|
+
# PROJ keeps using this structure after proj_context_set_fileapi returns,
|
|
42
|
+
# so it must be retained on the Ruby object to avoid GC invalidating it.
|
|
43
|
+
@proj_file_api = Api::ProjFileApi.new
|
|
44
|
+
@proj_file_api[:version] = 1
|
|
45
|
+
|
|
46
|
+
# Maps native address -> {proj_handle:, file:}. Retaining proj_handle
|
|
47
|
+
# prevents the MemoryPointer from being GCed while PROJ holds the address.
|
|
48
|
+
@file_api_handles = {}
|
|
49
|
+
|
|
50
|
+
@proj_file_api[:open_cbk] = self.method(:open_callback)
|
|
51
|
+
@proj_file_api[:read_cbk] = self.method(:read_callback)
|
|
52
|
+
@proj_file_api[:write_cbk] = self.method(:write_callback)
|
|
53
|
+
@proj_file_api[:seek_cbk] = self.method(:seek_callback)
|
|
54
|
+
@proj_file_api[:tell_cbk] = self.method(:tell_callback)
|
|
55
|
+
@proj_file_api[:close_cbk] = self.method(:close_callback)
|
|
56
|
+
@proj_file_api[:exists_cbk] = self.method(:exists_callback)
|
|
57
|
+
@proj_file_api[:mkdir_cbk] = self.method(:mkdir_callback)
|
|
58
|
+
@proj_file_api[:unlink_cbk] = self.method(:unlink_callback)
|
|
59
|
+
@proj_file_api[:rename_cbk] = self.method(:rename_callback)
|
|
60
|
+
|
|
61
|
+
result = Api.proj_context_set_fileapi(context, @proj_file_api, nil)
|
|
62
|
+
|
|
63
|
+
if result != 1
|
|
64
|
+
Error.check_object(self)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Open file. Return NULL if error
|
|
69
|
+
def open_callback(context, path, access_mode, user_data)
|
|
70
|
+
file = self.open(path, access_mode)
|
|
71
|
+
return nil unless file
|
|
72
|
+
register_handle(file)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Read sizeBytes into buffer from current position and return number of bytes read
|
|
76
|
+
def read_callback(context, handle, buffer, size_bytes, user_data)
|
|
77
|
+
file = handle_to_file(handle)
|
|
78
|
+
data = self.read(file, size_bytes)
|
|
79
|
+
return 0 if data.nil? || data.empty?
|
|
80
|
+
|
|
81
|
+
read_bytes = [size_bytes, data.bytesize].min
|
|
82
|
+
buffer.put_bytes(0, data, 0, read_bytes)
|
|
83
|
+
read_bytes
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Write sizeBytes into buffer from current position and return number of bytes written
|
|
87
|
+
def write_callback(context, handle, buffer, size_bytes, user_data)
|
|
88
|
+
file = handle_to_file(handle)
|
|
89
|
+
data = buffer.get_bytes(0, size_bytes)
|
|
90
|
+
self.write(file, data)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Seek to offset using whence=SEEK_SET/SEEK_CUR/SEEK_END. Return TRUE in case of success
|
|
94
|
+
def seek_callback(context, handle, offset, whence, user_data)
|
|
95
|
+
file = handle_to_file(handle)
|
|
96
|
+
self.seek(file, offset, whence)
|
|
97
|
+
return 1 # True
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Return current file position
|
|
101
|
+
def tell_callback(context, handle, user_data)
|
|
102
|
+
file = handle_to_file(handle)
|
|
103
|
+
self.tell(file)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Close file
|
|
107
|
+
def close_callback(context, handle, user_data)
|
|
108
|
+
file = handle_to_file(handle)
|
|
109
|
+
self.close(file)
|
|
110
|
+
unregister_handle(handle)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Return TRUE if a file exists
|
|
114
|
+
def exists_callback(context, path, user_data)
|
|
115
|
+
if self.exists(path)
|
|
116
|
+
1
|
|
117
|
+
else
|
|
118
|
+
0
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Return TRUE if directory exists or could be created
|
|
123
|
+
def mkdir_callback(context, path, user_data)
|
|
124
|
+
if self.mkdir(path)
|
|
125
|
+
1
|
|
126
|
+
else
|
|
127
|
+
0
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Return TRUE if file could be removed
|
|
132
|
+
def unlink_callback(context, path, user_data)
|
|
133
|
+
if self.unlink(path)
|
|
134
|
+
1
|
|
135
|
+
else
|
|
136
|
+
0
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Return TRUE if file could be renamed
|
|
141
|
+
def rename_callback(context, original_path, new_path, user_data)
|
|
142
|
+
if self.rename(original_path, new_path)
|
|
143
|
+
1
|
|
144
|
+
else
|
|
145
|
+
0
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Create an opaque handle for PROJ and associate it with a file object.
|
|
150
|
+
# The MemoryPointer is retained to prevent GC while PROJ holds the address.
|
|
151
|
+
def register_handle(file)
|
|
152
|
+
proj_handle = FFI::MemoryPointer.new(:pointer)
|
|
153
|
+
@file_api_handles[proj_handle.address] = { proj_handle: proj_handle, file: file }
|
|
154
|
+
proj_handle
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def handle_to_file(handle)
|
|
158
|
+
@file_api_handles[handle.address][:file]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def unregister_handle(handle)
|
|
162
|
+
@file_api_handles.delete(handle.address)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|