rgeo-dschee 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +29 -0
  3. data/ext/geos_c_impl/coordinates.c +65 -0
  4. data/ext/geos_c_impl/coordinates.h +2 -0
  5. data/ext/geos_c_impl/extconf.rb +43 -0
  6. data/ext/geos_c_impl/factory.c +995 -0
  7. data/ext/geos_c_impl/factory.h +238 -0
  8. data/ext/geos_c_impl/geometry.c +1093 -0
  9. data/ext/geos_c_impl/geometry.h +23 -0
  10. data/ext/geos_c_impl/geometry_collection.c +757 -0
  11. data/ext/geos_c_impl/geometry_collection.h +46 -0
  12. data/ext/geos_c_impl/line_string.c +675 -0
  13. data/ext/geos_c_impl/line_string.h +32 -0
  14. data/ext/geos_c_impl/main.c +40 -0
  15. data/ext/geos_c_impl/point.c +236 -0
  16. data/ext/geos_c_impl/point.h +30 -0
  17. data/ext/geos_c_impl/polygon.c +359 -0
  18. data/ext/geos_c_impl/polygon.h +43 -0
  19. data/ext/geos_c_impl/preface.h +38 -0
  20. data/ext/proj4_c_impl/extconf.rb +62 -0
  21. data/ext/proj4_c_impl/main.c +315 -0
  22. data/lib/rgeo.rb +89 -0
  23. data/lib/rgeo/cartesian.rb +25 -0
  24. data/lib/rgeo/cartesian/analysis.rb +77 -0
  25. data/lib/rgeo/cartesian/bounding_box.rb +398 -0
  26. data/lib/rgeo/cartesian/calculations.rb +113 -0
  27. data/lib/rgeo/cartesian/factory.rb +347 -0
  28. data/lib/rgeo/cartesian/feature_classes.rb +100 -0
  29. data/lib/rgeo/cartesian/feature_methods.rb +88 -0
  30. data/lib/rgeo/cartesian/interface.rb +135 -0
  31. data/lib/rgeo/coord_sys.rb +43 -0
  32. data/lib/rgeo/coord_sys/cs/entities.rb +1315 -0
  33. data/lib/rgeo/coord_sys/cs/factories.rb +148 -0
  34. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +272 -0
  35. data/lib/rgeo/coord_sys/proj4.rb +293 -0
  36. data/lib/rgeo/coord_sys/srs_database/interface.rb +115 -0
  37. data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +140 -0
  38. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +62 -0
  39. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +63 -0
  40. data/lib/rgeo/error.rb +27 -0
  41. data/lib/rgeo/feature.rb +54 -0
  42. data/lib/rgeo/feature/curve.rb +111 -0
  43. data/lib/rgeo/feature/factory.rb +278 -0
  44. data/lib/rgeo/feature/factory_generator.rb +96 -0
  45. data/lib/rgeo/feature/geometry.rb +624 -0
  46. data/lib/rgeo/feature/geometry_collection.rb +95 -0
  47. data/lib/rgeo/feature/line.rb +26 -0
  48. data/lib/rgeo/feature/line_string.rb +60 -0
  49. data/lib/rgeo/feature/linear_ring.rb +26 -0
  50. data/lib/rgeo/feature/mixins.rb +143 -0
  51. data/lib/rgeo/feature/multi_curve.rb +71 -0
  52. data/lib/rgeo/feature/multi_line_string.rb +26 -0
  53. data/lib/rgeo/feature/multi_point.rb +33 -0
  54. data/lib/rgeo/feature/multi_polygon.rb +57 -0
  55. data/lib/rgeo/feature/multi_surface.rb +73 -0
  56. data/lib/rgeo/feature/point.rb +84 -0
  57. data/lib/rgeo/feature/polygon.rb +97 -0
  58. data/lib/rgeo/feature/surface.rb +79 -0
  59. data/lib/rgeo/feature/types.rb +284 -0
  60. data/lib/rgeo/geographic.rb +40 -0
  61. data/lib/rgeo/geographic/factory.rb +450 -0
  62. data/lib/rgeo/geographic/interface.rb +489 -0
  63. data/lib/rgeo/geographic/proj4_projector.rb +58 -0
  64. data/lib/rgeo/geographic/projected_feature_classes.rb +107 -0
  65. data/lib/rgeo/geographic/projected_feature_methods.rb +212 -0
  66. data/lib/rgeo/geographic/projected_window.rb +383 -0
  67. data/lib/rgeo/geographic/simple_mercator_projector.rb +110 -0
  68. data/lib/rgeo/geographic/spherical_feature_classes.rb +100 -0
  69. data/lib/rgeo/geographic/spherical_feature_methods.rb +134 -0
  70. data/lib/rgeo/geographic/spherical_math.rb +188 -0
  71. data/lib/rgeo/geos.rb +89 -0
  72. data/lib/rgeo/geos/capi_factory.rb +470 -0
  73. data/lib/rgeo/geos/capi_feature_classes.rb +129 -0
  74. data/lib/rgeo/geos/ffi_factory.rb +592 -0
  75. data/lib/rgeo/geos/ffi_feature_classes.rb +83 -0
  76. data/lib/rgeo/geos/ffi_feature_methods.rb +574 -0
  77. data/lib/rgeo/geos/interface.rb +202 -0
  78. data/lib/rgeo/geos/utils.rb +74 -0
  79. data/lib/rgeo/geos/zm_factory.rb +405 -0
  80. data/lib/rgeo/geos/zm_feature_classes.rb +80 -0
  81. data/lib/rgeo/geos/zm_feature_methods.rb +344 -0
  82. data/lib/rgeo/impl_helper.rb +19 -0
  83. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +185 -0
  84. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +61 -0
  85. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +146 -0
  86. data/lib/rgeo/impl_helper/basic_point_methods.rb +104 -0
  87. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +87 -0
  88. data/lib/rgeo/impl_helper/math.rb +14 -0
  89. data/lib/rgeo/impl_helper/utils.rb +29 -0
  90. data/lib/rgeo/version.rb +3 -0
  91. data/lib/rgeo/wkrep.rb +37 -0
  92. data/lib/rgeo/wkrep/wkb_generator.rb +201 -0
  93. data/lib/rgeo/wkrep/wkb_parser.rb +251 -0
  94. data/lib/rgeo/wkrep/wkt_generator.rb +207 -0
  95. data/lib/rgeo/wkrep/wkt_parser.rb +415 -0
  96. data/lib/rgeo/yaml.rb +23 -0
  97. data/test/cartesian_analysis_test.rb +65 -0
  98. data/test/cartesian_bbox_test.rb +123 -0
  99. data/test/common/factory_tests.rb +78 -0
  100. data/test/common/geometry_collection_tests.rb +237 -0
  101. data/test/common/line_string_tests.rb +330 -0
  102. data/test/common/multi_line_string_tests.rb +182 -0
  103. data/test/common/multi_point_tests.rb +200 -0
  104. data/test/common/multi_polygon_tests.rb +191 -0
  105. data/test/common/point_tests.rb +370 -0
  106. data/test/common/polygon_tests.rb +261 -0
  107. data/test/coord_sys/ogc_cs_test.rb +342 -0
  108. data/test/coord_sys/proj4_srs_data_test.rb +41 -0
  109. data/test/coord_sys/proj4_test.rb +150 -0
  110. data/test/coord_sys/sr_org_test.rb +32 -0
  111. data/test/coord_sys/url_reader_test.rb +42 -0
  112. data/test/geos_capi/factory_test.rb +31 -0
  113. data/test/geos_capi/geometry_collection_test.rb +24 -0
  114. data/test/geos_capi/line_string_test.rb +24 -0
  115. data/test/geos_capi/misc_test.rb +116 -0
  116. data/test/geos_capi/multi_line_string_test.rb +24 -0
  117. data/test/geos_capi/multi_point_test.rb +24 -0
  118. data/test/geos_capi/multi_polygon_test.rb +39 -0
  119. data/test/geos_capi/parsing_unparsing_test.rb +40 -0
  120. data/test/geos_capi/point_test.rb +72 -0
  121. data/test/geos_capi/polygon_test.rb +154 -0
  122. data/test/geos_capi/zmfactory_test.rb +57 -0
  123. data/test/geos_ffi/factory_test.rb +31 -0
  124. data/test/geos_ffi/geometry_collection_test.rb +24 -0
  125. data/test/geos_ffi/line_string_test.rb +24 -0
  126. data/test/geos_ffi/misc_test.rb +63 -0
  127. data/test/geos_ffi/multi_line_string_test.rb +24 -0
  128. data/test/geos_ffi/multi_point_test.rb +24 -0
  129. data/test/geos_ffi/multi_polygon_test.rb +33 -0
  130. data/test/geos_ffi/parsing_unparsing_test.rb +41 -0
  131. data/test/geos_ffi/point_test.rb +77 -0
  132. data/test/geos_ffi/polygon_test.rb +46 -0
  133. data/test/geos_ffi/zmfactory_test.rb +58 -0
  134. data/test/mixins_test.rb +141 -0
  135. data/test/oneoff_test.rb +26 -0
  136. data/test/projected_geographic/factory_test.rb +25 -0
  137. data/test/projected_geographic/geometry_collection_test.rb +24 -0
  138. data/test/projected_geographic/line_string_test.rb +24 -0
  139. data/test/projected_geographic/multi_line_string_test.rb +26 -0
  140. data/test/projected_geographic/multi_point_test.rb +30 -0
  141. data/test/projected_geographic/multi_polygon_test.rb +25 -0
  142. data/test/projected_geographic/point_test.rb +51 -0
  143. data/test/projected_geographic/polygon_test.rb +24 -0
  144. data/test/simple_cartesian/calculations_test.rb +99 -0
  145. data/test/simple_cartesian/factory_test.rb +27 -0
  146. data/test/simple_cartesian/geometry_collection_test.rb +30 -0
  147. data/test/simple_cartesian/line_string_test.rb +31 -0
  148. data/test/simple_cartesian/multi_line_string_test.rb +28 -0
  149. data/test/simple_cartesian/multi_point_test.rb +31 -0
  150. data/test/simple_cartesian/multi_polygon_test.rb +31 -0
  151. data/test/simple_cartesian/point_test.rb +50 -0
  152. data/test/simple_cartesian/polygon_test.rb +28 -0
  153. data/test/simple_mercator/factory_test.rb +25 -0
  154. data/test/simple_mercator/geometry_collection_test.rb +24 -0
  155. data/test/simple_mercator/line_string_test.rb +24 -0
  156. data/test/simple_mercator/multi_line_string_test.rb +26 -0
  157. data/test/simple_mercator/multi_point_test.rb +29 -0
  158. data/test/simple_mercator/multi_polygon_test.rb +25 -0
  159. data/test/simple_mercator/point_test.rb +55 -0
  160. data/test/simple_mercator/polygon_test.rb +24 -0
  161. data/test/simple_mercator/window_test.rb +173 -0
  162. data/test/spherical_geographic/calculations_test.rb +167 -0
  163. data/test/spherical_geographic/factory_test.rb +27 -0
  164. data/test/spherical_geographic/geometry_collection_test.rb +31 -0
  165. data/test/spherical_geographic/line_string_test.rb +31 -0
  166. data/test/spherical_geographic/multi_line_string_test.rb +29 -0
  167. data/test/spherical_geographic/multi_point_test.rb +31 -0
  168. data/test/spherical_geographic/multi_polygon_test.rb +31 -0
  169. data/test/spherical_geographic/point_test.rb +78 -0
  170. data/test/spherical_geographic/polygon_test.rb +28 -0
  171. data/test/types_test.rb +42 -0
  172. data/test/wkrep/wkb_generator_test.rb +185 -0
  173. data/test/wkrep/wkb_parser_test.rb +293 -0
  174. data/test/wkrep/wkt_generator_test.rb +294 -0
  175. data/test/wkrep/wkt_parser_test.rb +412 -0
  176. metadata +386 -0
@@ -0,0 +1,100 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Cartesian feature classes
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Cartesian
9
+ class PointImpl # :nodoc:
10
+ include ::RGeo::Feature::Point
11
+ include ::RGeo::ImplHelper::BasicGeometryMethods
12
+ include ::RGeo::ImplHelper::BasicPointMethods
13
+ include ::RGeo::Cartesian::GeometryMethods
14
+ include ::RGeo::Cartesian::PointMethods
15
+
16
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Point).include_in_class(self, true)
17
+ end
18
+
19
+ class LineStringImpl # :nodoc:
20
+ include ::RGeo::Feature::LineString
21
+ include ::RGeo::ImplHelper::BasicGeometryMethods
22
+ include ::RGeo::ImplHelper::BasicLineStringMethods
23
+ include ::RGeo::Cartesian::GeometryMethods
24
+ include ::RGeo::Cartesian::LineStringMethods
25
+
26
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LineString).include_in_class(self, true)
27
+ end
28
+
29
+ class LineImpl # :nodoc:
30
+ include ::RGeo::Feature::Line
31
+ include ::RGeo::ImplHelper::BasicGeometryMethods
32
+ include ::RGeo::ImplHelper::BasicLineStringMethods
33
+ include ::RGeo::ImplHelper::BasicLineMethods
34
+ include ::RGeo::Cartesian::GeometryMethods
35
+ include ::RGeo::Cartesian::LineStringMethods
36
+
37
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Line).include_in_class(self, true)
38
+ end
39
+
40
+ class LinearRingImpl # :nodoc:
41
+ include ::RGeo::Feature::LinearRing
42
+ include ::RGeo::ImplHelper::BasicGeometryMethods
43
+ include ::RGeo::ImplHelper::BasicLineStringMethods
44
+ include ::RGeo::ImplHelper::BasicLinearRingMethods
45
+ include ::RGeo::Cartesian::GeometryMethods
46
+ include ::RGeo::Cartesian::LineStringMethods
47
+
48
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LinearRing).include_in_class(self, true)
49
+ end
50
+
51
+ class PolygonImpl # :nodoc:
52
+ include ::RGeo::Feature::Polygon
53
+ include ::RGeo::ImplHelper::BasicGeometryMethods
54
+ include ::RGeo::ImplHelper::BasicPolygonMethods
55
+ include ::RGeo::Cartesian::GeometryMethods
56
+
57
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Polygon).include_in_class(self, true)
58
+ end
59
+
60
+ class GeometryCollectionImpl # :nodoc:
61
+ include ::RGeo::Feature::GeometryCollection
62
+ include ::RGeo::ImplHelper::BasicGeometryMethods
63
+ include ::RGeo::ImplHelper::BasicGeometryCollectionMethods
64
+ include ::RGeo::Cartesian::GeometryMethods
65
+
66
+ Feature::MixinCollection::GLOBAL.for_type(Feature::GeometryCollection).include_in_class(self, true)
67
+ end
68
+
69
+ class MultiPointImpl # :nodoc:
70
+ include ::RGeo::Feature::MultiPoint
71
+ include ::RGeo::ImplHelper::BasicGeometryMethods
72
+ include ::RGeo::ImplHelper::BasicGeometryCollectionMethods
73
+ include ::RGeo::ImplHelper::BasicMultiPointMethods
74
+ include ::RGeo::Cartesian::GeometryMethods
75
+
76
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPoint).include_in_class(self, true)
77
+ end
78
+
79
+ class MultiLineStringImpl # :nodoc:
80
+ include ::RGeo::Feature::MultiLineString
81
+ include ::RGeo::ImplHelper::BasicGeometryMethods
82
+ include ::RGeo::ImplHelper::BasicGeometryCollectionMethods
83
+ include ::RGeo::ImplHelper::BasicMultiLineStringMethods
84
+ include ::RGeo::Cartesian::GeometryMethods
85
+ include ::RGeo::Cartesian::MultiLineStringMethods
86
+
87
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiLineString).include_in_class(self, true)
88
+ end
89
+
90
+ class MultiPolygonImpl # :nodoc:
91
+ include ::RGeo::Feature::MultiPolygon
92
+ include ::RGeo::ImplHelper::BasicGeometryMethods
93
+ include ::RGeo::ImplHelper::BasicGeometryCollectionMethods
94
+ include ::RGeo::ImplHelper::BasicMultiPolygonMethods
95
+ include ::RGeo::Cartesian::GeometryMethods
96
+
97
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPolygon).include_in_class(self, true)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,88 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Cartesian common methods
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Cartesian
9
+ module GeometryMethods # :nodoc:
10
+ def srid
11
+ factory.srid
12
+ end
13
+
14
+ def envelope
15
+ BoundingBox.new(factory).add(self).to_geometry
16
+ end
17
+ end
18
+
19
+ module PointMethods # :nodoc:
20
+ def distance(rhs_)
21
+ rhs_ = ::RGeo::Feature.cast(rhs_, @factory)
22
+ case rhs_
23
+ when PointImpl
24
+ dx_ = @x - rhs_.x
25
+ dy_ = @y - rhs_.y
26
+ ::Math.sqrt(dx_ * dx_ + dy_ * dy_)
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def buffer(distance_)
33
+ point_count_ = factory.property(:buffer_resolution) * 4
34
+ angle_ = -::Math::PI * 2.0 / point_count_
35
+ points_ = (0...point_count_).map do |i_|
36
+ r_ = angle_ * i_
37
+ factory.point(@x + distance_ * ::Math.cos(r_), @y + distance_ * ::Math.sin(r_))
38
+ end
39
+ factory.polygon(factory.linear_ring(points_))
40
+ end
41
+ end
42
+
43
+ module LineStringMethods # :nodoc:
44
+ def _segments
45
+ unless defined?(@segments)
46
+ @segments = (0..num_points - 2).map do |i_|
47
+ Segment.new(point_n(i_), point_n(i_ + 1))
48
+ end
49
+ end
50
+ @segments
51
+ end
52
+
53
+ def is_simple?
54
+ segs_ = _segments
55
+ len_ = segs_.length
56
+ return false if segs_.any?(&:degenerate?)
57
+ return true if len_ == 1
58
+ return segs_[0].s != segs_[1].e if len_ == 2
59
+ segs_.each_with_index do |seg_, index_|
60
+ nindex_ = index_ + 1
61
+ nindex_ = nil if nindex_ == len_
62
+ return false if nindex_ && seg_.contains_point?(segs_[nindex_].e)
63
+ pindex_ = index_ - 1
64
+ pindex_ = nil if pindex_ < 0
65
+ return false if pindex_ && seg_.contains_point?(segs_[pindex_].s)
66
+ next unless nindex_
67
+ oindex_ = nindex_ + 1
68
+ while oindex_ < len_
69
+ oseg_ = segs_[oindex_]
70
+ return false if !(index_ == 0 && oindex_ == len_ - 1 && seg_.s == oseg_.e) && seg_.intersects_segment?(oseg_)
71
+ oindex_ += 1
72
+ end
73
+ end
74
+ true
75
+ end
76
+
77
+ def length
78
+ _segments.inject(0.0) { |sum_, seg_| sum_ + seg_.length }
79
+ end
80
+ end
81
+
82
+ module MultiLineStringMethods # :nodoc:
83
+ def length
84
+ inject(0.0) { |sum_, geom_| sum_ + geom_.length }
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,135 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Cartesian toplevel interface
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Cartesian
9
+ class << self
10
+ # Creates and returns a cartesian factory of the preferred
11
+ # Cartesian implementation.
12
+ #
13
+ # The actual implementation returned depends on which ruby
14
+ # interpreter is running and what libraries are available.
15
+ # RGeo will try to provide a fully-functional and performant
16
+ # implementation if possible. If not, the simple Cartesian
17
+ # implementation will be returned.
18
+ # In practice, this means it returns a Geos implementation if
19
+ # available; otherwise it falls back to the simple implementation.
20
+ #
21
+ # The given options are passed to the factory's constructor.
22
+ # What options are available depends on the particular
23
+ # implementation. See RGeo::Geos.factory and
24
+ # RGeo::Cartesian.simple_factory for details. Unsupported options
25
+ # are ignored.
26
+
27
+ def preferred_factory(opts_ = {})
28
+ if ::RGeo::Geos.supported?
29
+ ::RGeo::Geos.factory(opts_)
30
+ else
31
+ simple_factory(opts_)
32
+ end
33
+ end
34
+ alias_method :factory, :preferred_factory
35
+
36
+ # Returns a factory for the simple Cartesian implementation. This
37
+ # implementation provides all SFS 1.1 types, and also allows Z and
38
+ # M coordinates. It does not depend on external libraries, and is
39
+ # thus always available, but it does not implement many of the more
40
+ # advanced geometric operations. These limitations are:
41
+ #
42
+ # * Relational operators such as Feature::Geometry#intersects? are
43
+ # not implemented for most types.
44
+ # * Relational constructors such as Feature::Geometry#union are
45
+ # not implemented for most types.
46
+ # * Buffer and convex hull calculations are not implemented for most
47
+ # types. Boundaries are available except for GeometryCollection.
48
+ # * Length calculations are available, but areas are not. Distances
49
+ # are available only between points.
50
+ # * Equality and simplicity evaluation are implemented for some but
51
+ # not all types.
52
+ # * Assertions for polygons and multipolygons are not implemented.
53
+ #
54
+ # Unimplemented operations may raise Error::UnsupportedOperation
55
+ # if invoked.
56
+ #
57
+ # Options include:
58
+ #
59
+ # [<tt>:srid</tt>]
60
+ # Set the SRID returned by geometries created by this factory.
61
+ # Default is 0.
62
+ # [<tt>:proj4</tt>]
63
+ # The coordinate system in Proj4 format, either as a
64
+ # CoordSys::Proj4 object or as a string or hash representing the
65
+ # proj4 format. Optional.
66
+ # [<tt>:coord_sys</tt>]
67
+ # The coordinate system in OGC form, either as a subclass of
68
+ # CoordSys::CS::CoordinateSystem, or as a string in WKT format.
69
+ # Optional.
70
+ # [<tt>:srs_database</tt>]
71
+ # Optional. If provided, the value should be an implementation of
72
+ # CoordSys::SRSDatabase::Interface. If both this and an SRID are
73
+ # provided, they are used to look up the proj4 and coord_sys
74
+ # objects from a spatial reference system database.
75
+ # [<tt>:has_z_coordinate</tt>]
76
+ # Support a Z coordinate. Default is false.
77
+ # [<tt>:has_m_coordinate</tt>]
78
+ # Support an M coordinate. Default is false.
79
+ # [<tt>:uses_lenient_assertions</tt>]
80
+ # If set to true, assertion checking is disabled. This includes
81
+ # simplicity checking on LinearRing, and validity checks on
82
+ # Polygon and MultiPolygon. This may speed up creation of certain
83
+ # objects, at the expense of not doing the proper checking for
84
+ # OGC compliance. Default is false.
85
+ # [<tt>:wkt_parser</tt>]
86
+ # Configure the parser for WKT. The value is a hash of
87
+ # configuration parameters for WKRep::WKTParser.new. Default is
88
+ # the empty hash, indicating the default configuration for
89
+ # WKRep::WKTParser.
90
+ # [<tt>:wkb_parser</tt>]
91
+ # Configure the parser for WKB. The value is a hash of
92
+ # configuration parameters for WKRep::WKBParser.new. Default is
93
+ # the empty hash, indicating the default configuration for
94
+ # WKRep::WKBParser.
95
+ # [<tt>:wkt_generator</tt>]
96
+ # Configure the generator for WKT. The value is a hash of
97
+ # configuration parameters for WKRep::WKTGenerator.new.
98
+ # Default is <tt>{:convert_case => :upper}</tt>.
99
+ # [<tt>:wkb_generator</tt>]
100
+ # Configure the generator for WKT. The value is a hash of
101
+ # configuration parameters for WKRep::WKTGenerator.new.
102
+ # Default is the empty hash, indicating the default configuration
103
+ # for WKRep::WKBGenerator.
104
+
105
+ def simple_factory(opts_ = {})
106
+ Cartesian::Factory.new(opts_)
107
+ end
108
+
109
+ # Returns a Feature::FactoryGenerator that creates preferred
110
+ # factories. The given options are used as the default options.
111
+ #
112
+ # A common case for this is to provide the <tt>:srs_database</tt>
113
+ # as a default. Then, the factory generator need only be passed
114
+ # an SRID and it will automatically fetch the appropriate Proj4
115
+ # and CoordSys objects.
116
+
117
+ def preferred_factory_generator(defaults_ = {})
118
+ ::Proc.new { |c_| preferred_factory(defaults_.merge(c_)) }
119
+ end
120
+ alias_method :factory_generator, :preferred_factory_generator
121
+
122
+ # Returns a Feature::FactoryGenerator that creates simple factories.
123
+ # The given options are used as the default options.
124
+ #
125
+ # A common case for this is to provide the <tt>:srs_database</tt>
126
+ # as a default. Then, the factory generator need only be passed
127
+ # an SRID and it will automatically fetch the appropriate Proj4
128
+ # and CoordSys objects.
129
+
130
+ def simple_factory_generator(defaults_ = {})
131
+ ::Proc.new { |c_| simple_factory(defaults_.merge(c_)) }
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,43 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Coordinate systems for RGeo
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ # This module provides data structures and tools related to coordinate
9
+ # systems and coordinate transforms. It comprises the following parts:
10
+ #
11
+ # RGeo::CoordSys::Proj4 is a wrapper around the proj4 library, which
12
+ # defines a commonly-used syntax for specifying geographic and projected
13
+ # coordinate systems, and performs coordinate transformations.
14
+ #
15
+ # The RGeo::CoordSys::CS module contains an implementation of the CS
16
+ # (coordinate systems) package of the OGC Coordinate Transform spec.
17
+ # This includes classes for representing ellipsoids, datums, coordinate
18
+ # systems, and other related concepts, as well as a parser for the WKT
19
+ # format for specifying coordinate systems.
20
+ #
21
+ # The RGeo::CoordSys::SRSDatabase module contains tools for accessing
22
+ # spatial reference databases, from which you can look up coordinate
23
+ # system specifications. You can access the <tt>spatial_ref_sys</tt>
24
+ # table provided with OGC-compliant spatial databases such as PostGIS,
25
+ # read the databases provided with the proj4 library, or access URLs
26
+ # such as those provided by spatialreference.org.
27
+
28
+ module CoordSys
29
+ end
30
+ end
31
+
32
+ # Implementation files
33
+ begin
34
+ require "rgeo/coord_sys/proj4_c_impl"
35
+ rescue ::LoadError; end
36
+ require "rgeo/coord_sys/proj4"
37
+ require "rgeo/coord_sys/cs/factories"
38
+ require "rgeo/coord_sys/cs/entities"
39
+ require "rgeo/coord_sys/cs/wkt_parser"
40
+ require "rgeo/coord_sys/srs_database/interface.rb"
41
+ require "rgeo/coord_sys/srs_database/proj4_data.rb"
42
+ require "rgeo/coord_sys/srs_database/url_reader.rb"
43
+ require "rgeo/coord_sys/srs_database/sr_org.rb"
@@ -0,0 +1,1315 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # OGC CS objects for RGeo
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module CoordSys
9
+ module CS
10
+ # An axis orientation constant for AxisInfo.
11
+ # Unknown or unspecified axis orientation. This can be used for
12
+ # local or fitted coordinate systems.
13
+ AO_OTHER = 0
14
+
15
+ # An axis orientation constant for AxisInfo.
16
+ # Increasing ordinates values go North. This is usually used for
17
+ # Grid Y coordinates and Latitude.
18
+ AO_NORTH = 1
19
+
20
+ # An axis orientation constant for AxisInfo.
21
+ # Increasing ordinates values go South. This is rarely used.
22
+ AO_SOUTH = 2
23
+
24
+ # An axis orientation constant for AxisInfo.
25
+ # Increasing ordinates values go East. This is rarely used.
26
+ AO_EAST = 3
27
+
28
+ # An axis orientation constant for AxisInfo.
29
+ # Increasing ordinates values go West. This is usually used for
30
+ # Grid X coordinates and Longitude.
31
+ AO_WEST = 4
32
+
33
+ # An axis orientation constant for AxisInfo.
34
+ # Increasing ordinates values go up. This is used for vertical
35
+ # coordinate systems.
36
+ AO_UP = 5
37
+
38
+ # An axis orientation constant for AxisInfo.
39
+ # Increasing ordinates values go down. This is used for vertical
40
+ # coordinate systems.
41
+ AO_DOWN = 6
42
+
43
+ # A datum type constant for HorizontalDatum.
44
+ # Lowest possible value for horizontal datum types.
45
+ HD_MIN = 1000
46
+
47
+ # A datum type constant for HorizontalDatum.
48
+ # Unspecified horizontal datum type. Horizontal datums with this
49
+ # type should never supply a conversion to WGS84 using Bursa Wolf
50
+ # parameters.
51
+ HD_OTHER = 1000
52
+
53
+ # A datum type constant for HorizontalDatum.
54
+ # These datums, such as ED50, NAD27 and NAD83, have been designed
55
+ # to support horizontal positions on the ellipsoid as opposed to
56
+ # positions in 3-D space. These datums were designed mainly to
57
+ # support a horizontal component of a position in a domain of
58
+ # limited extent, such as a country, a region or a continent.
59
+ HD_CLASSIC = 1001
60
+
61
+ # A datum type constant for HorizontalDatum.
62
+ # A geocentric datum is a "satellite age" modern geodetic datum
63
+ # mainly of global extent, such as WGS84 (used in GPS), PZ90 (used
64
+ # in GLONASS) and ITRF. These datums were designed to support both
65
+ # a horizontal component of position and a vertical component of
66
+ # position (through ellipsoidal heights). The regional realizations
67
+ # of ITRF, such as ETRF, are also included in this category.
68
+ HD_GEOCENTRIC = 1002
69
+
70
+ # A datum type constant for HorizontalDatum.
71
+ # Highest possible value for horizontal datum types.
72
+ HD_MAX = 1999
73
+
74
+ # A datum type constant for VerticalDatum.
75
+ # Lowest possible value for vertical datum types.
76
+ VD_MIN = 2000
77
+
78
+ # A datum type constant for VerticalDatum.
79
+ # Unspecified vertical datum type.
80
+ VD_OTHER = 2000
81
+
82
+ # A datum type constant for VerticalDatum.
83
+ # A vertical datum for orthometric heights that are measured along
84
+ # the plumb line.
85
+ VD_ORTHOMETRIC = 2001
86
+
87
+ # A datum type constant for VerticalDatum.
88
+ # A vertical datum for ellipsoidal heights that are measured along
89
+ # the normal to the ellipsoid used in the definition of horizontal
90
+ # datum.
91
+ VD_ELLIPSOIDAL = 2002
92
+
93
+ # A datum type constant for VerticalDatum.
94
+ # The vertical datum of altitudes or heights in the atmosphere.
95
+ # These are approximations of orthometric heights obtained with the
96
+ # help of a barometer or a barometric altimeter. These values are
97
+ # usually expressed in one of the following units: meters, feet,
98
+ # millibars (used to measure pressure levels), or theta value (units
99
+ # used to measure geopotential height).
100
+ VD_ALTITUDE_BAROMETRIC = 2003
101
+
102
+ # A datum type constant for VerticalDatum.
103
+ # A normal height system.
104
+ VD_NORMAL = 2004
105
+
106
+ # A datum type constant for VerticalDatum.
107
+ # A vertical datum of geoid model derived heights, also called
108
+ # GPS-derived heights. These heights are approximations of
109
+ # orthometric heights (H), constructed from the ellipsoidal heights
110
+ # (h) by the use of the given geoid undulation model (N) through
111
+ # the equation: H=h-N.
112
+ VD_GEOID_MODE_DERIVED = 2005
113
+
114
+ # A datum type constant for VerticalDatum.
115
+ # This attribute is used to support the set of datums generated for
116
+ # hydrographic engineering projects where depth measurements below
117
+ # sea level are needed. It is often called a hydrographic or a
118
+ # marine datum. Depths are measured in the direction perpendicular
119
+ # (approximately) to the actual equipotential surfaces of the
120
+ # earth's gravity field, using such procedures as echo-sounding.
121
+ VD_DEPTH = 2006
122
+
123
+ # A datum type constant for VerticalDatum.
124
+ # Highest possible value for vertical datum types.
125
+ VD_MAX = 2999
126
+
127
+ # A datum type constant for LocalDatum.
128
+ # Lowest possible value for local datum types.
129
+ LD_MIN = 10_000
130
+
131
+ # A datum type constant for LocalDatum.
132
+ # Highest possible value for local datum types.
133
+ LD_MAX = 32_767
134
+
135
+ # This is a base class for all OGC coordinate system objects.
136
+ # This includes both interfaces and data types from the OGC
137
+ # Coordinate Transformation spec.
138
+ #
139
+ # This is a non-instantiable abstract class.
140
+
141
+ class Base
142
+ # Standard object inspection output
143
+
144
+ def inspect
145
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{to_wkt}>"
146
+ end
147
+
148
+ # Tests for equality. Two objects are defined as equal if they
149
+ # have the same type (class) and the same WKT representation.
150
+
151
+ def eql?(rhs_)
152
+ rhs_.class == self.class && rhs_.to_wkt == to_wkt
153
+ end
154
+ alias_method :==, :eql?
155
+
156
+ # Standard hash code
157
+
158
+ def hash
159
+ @hash ||= to_wkt.hash
160
+ end
161
+
162
+ # Returns the default WKT representation.
163
+
164
+ def to_s
165
+ to_wkt
166
+ end
167
+
168
+ # Computes the WKT representation. Options include:
169
+ #
170
+ # [<tt>:standard_brackets</tt>]
171
+ # If set to true, outputs parentheses rather than square
172
+ # brackets. Default is false.
173
+
174
+ def to_wkt(opts_ = {})
175
+ if opts_[:standard_brackets]
176
+ @standard_wkt ||= _to_wkt("(", ")")
177
+ else
178
+ @square_wkt ||= _to_wkt("[", "]")
179
+ end
180
+ end
181
+
182
+ def _to_wkt(open_, close_) # :nodoc:
183
+ content_ = _wkt_content(open_, close_).map { |obj_| ",#{obj_}" }.join
184
+ if defined?(@authority) && @authority
185
+ authority_ = ",AUTHORITY#{open_}#{@authority.inspect},#{@authority_code.inspect}#{close_}"
186
+ else
187
+ authority_ = ""
188
+ end
189
+ if defined?(@extensions) && @extensions
190
+ extensions_ = @extensions.map { |k_, v_| ",EXTENSION#{open_}#{k_.inspect},#{v_.inspect}#{close_}" }.join
191
+ else
192
+ extensions_ = ""
193
+ end
194
+ "#{_wkt_typename}#{open_}#{@name.inspect}#{content_}#{extensions_}#{authority_}#{close_}"
195
+ end
196
+
197
+ # Marshal support
198
+
199
+ def marshal_dump # :nodoc:
200
+ to_wkt
201
+ end
202
+
203
+ def marshal_load(data_) # :nodoc:
204
+ data_ = data_["wkt"] if data_.is_a?(::Hash)
205
+ temp_ = CS.create_from_wkt(data_)
206
+ if temp_.class == self.class
207
+ temp_.instance_variables.each do |iv_|
208
+ instance_variable_set(iv_, temp_.instance_variable_get(iv_))
209
+ end
210
+ else
211
+ raise ::TypeError, "Bad Marshal data"
212
+ end
213
+ end
214
+
215
+ # Psych support
216
+
217
+ def encode_with(coder_) # :nodoc:
218
+ coder_["wkt"] = to_wkt
219
+ end
220
+
221
+ def init_with(coder_) # :nodoc:
222
+ temp_ = CS.create_from_wkt(coder_.type == :scalar ? coder_.scalar : coder_["wkt"])
223
+ if temp_.class == self.class
224
+ temp_.instance_variables.each do |iv_|
225
+ instance_variable_set(iv_, temp_.instance_variable_get(iv_))
226
+ end
227
+ else
228
+ raise ::TypeError, "Bad YAML data"
229
+ end
230
+ end
231
+
232
+ class << self
233
+ private :new
234
+ end
235
+ end
236
+
237
+ # == OGC spec description
238
+ #
239
+ # Details of axis. This is used to label axes, and indicate the
240
+ # orientation.
241
+
242
+ class AxisInfo < Base
243
+ # :stopdoc:
244
+ NAMES_BY_VALUE = %w(OTHER NORTH SOUTH EAST WEST UP DOWN)
245
+ # :startdoc:
246
+
247
+ def initialize(name_, orientation_) # :nodoc:
248
+ @name = name_
249
+ case orientation_
250
+ when ::String, ::Symbol
251
+ @orientation = NAMES_BY_VALUE.index(orientation_.to_s.upcase).to_i
252
+ else
253
+ @orientation = orientation_.to_i
254
+ end
255
+ end
256
+
257
+ # Human readable name for axis. Possible values are "X", "Y",
258
+ # "Long", "Lat" or any other short string.
259
+ attr_reader :name
260
+
261
+ # Gets enumerated value for orientation.
262
+ attr_reader :orientation
263
+
264
+ def _wkt_typename # :nodoc:
265
+ "AXIS"
266
+ end
267
+
268
+ def _wkt_content(_open_, _close_) # :nodoc:
269
+ [NAMES_BY_VALUE[@orientation]]
270
+ end
271
+
272
+ class << self
273
+ # Creates an AxisInfo. you must pass the human readable name for
274
+ # the axis (e.g. "X", "Y", "Long", "Lat", or other short string)
275
+ # and either an integer orientation code or a string. Possible
276
+ # orientation values are "<tt>OTHER</tt>", "<tt>NORTH</tt>",
277
+ # "<tt>SOUTH</tt>", "<tt>EAST</tt>", "<tt>WEST</tt>",
278
+ # "<tt>UP</tt>", and "<tt>DOWN</tt>", or the corresponding
279
+ # integer values 0-5.
280
+
281
+ def create(name_, orientation_)
282
+ new(name_, orientation_)
283
+ end
284
+ end
285
+ end
286
+
287
+ # == OGC spec description
288
+ #
289
+ # A named projection parameter value. The linear units of
290
+ # parameters' values match the linear units of the containing
291
+ # projected coordinate system. The angular units of parameter
292
+ # values match the angular units of the geographic coordinate
293
+ # system that the projected coordinate system is based on.
294
+
295
+ class ProjectionParameter < Base
296
+ def initialize(name_, value_) # :nodoc:
297
+ @name = name_
298
+ @value = value_.to_f
299
+ end
300
+
301
+ # The parameter name.
302
+ attr_reader :name
303
+
304
+ # The parameter value.
305
+ attr_reader :value
306
+
307
+ def _wkt_typename # :nodoc:
308
+ "PARAMETER"
309
+ end
310
+
311
+ def _wkt_content(_open_, _close_) # :nodoc:
312
+ [@value]
313
+ end
314
+
315
+ class << self
316
+ # Create a parameter given the name and value.
317
+
318
+ def create(name_, value_)
319
+ new(name_, value_)
320
+ end
321
+ end
322
+ end
323
+
324
+ # == OGC spec description
325
+ #
326
+ # Parameters for a geographic transformation into WGS84. The Bursa
327
+ # Wolf parameters should be applied to geocentric coordinates, where
328
+ # the X axis points towards the Greenwich Prime Meridian, the Y axis
329
+ # points East, and the Z axis points North.
330
+
331
+ class WGS84ConversionInfo < Base
332
+ def initialize(dx_, dy_, dz_, ex_, ey_, ez_, ppm_) # :nodoc:
333
+ @dx = dx_.to_f
334
+ @dy = dy_.to_f
335
+ @dz = dz_.to_f
336
+ @ex = ex_.to_f
337
+ @ey = ey_.to_f
338
+ @ez = ez_.to_f
339
+ @ppm = ppm_.to_f
340
+ end
341
+
342
+ # Bursa Wolf shift in meters.
343
+ attr_reader :dx
344
+
345
+ # Bursa Wolf shift in meters.
346
+ attr_reader :dy
347
+
348
+ # Bursa Wolf shift in meters.
349
+ attr_reader :dz
350
+
351
+ # Bursa Wolf rotation in arc seconds.
352
+ attr_reader :ex
353
+
354
+ # Bursa Wolf rotation in arc seconds.
355
+ attr_reader :ey
356
+
357
+ # Bursa Wolf rotation in arc seconds.
358
+ attr_reader :ez
359
+
360
+ # Bursa Wolf scaling in in parts per million.
361
+ attr_reader :ppm
362
+
363
+ def _to_wkt(open_, close_) # :nodoc:
364
+ "TOWGS84#{open_}#{@dx},#{@dy},#{@dz},#{@ex},#{@ey},#{@ez},#{@ppm}#{close_}"
365
+ end
366
+
367
+ class << self
368
+ # Create the horizontal datum shift transformation into WGS84,
369
+ # given the seven Bursa Wolf parameters.
370
+ # The Bursa Wolf shift should be in meters, the rotation in arc
371
+ # seconds, and the scaling in parts per million.
372
+
373
+ def create(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
374
+ new(dx_, dy_, dz_, ex_, ey_, ez_, ppm_)
375
+ end
376
+ end
377
+ end
378
+
379
+ # == OGC spec description
380
+ #
381
+ # A base interface for metadata applicable to coordinate system
382
+ # objects.
383
+ #
384
+ # The metadata items "Abbreviation"’, "Alias", "Authority",
385
+ # "AuthorityCode", "Name" and "Remarks" were specified in the Simple
386
+ # Features interfaces, so they have been kept here.
387
+ #
388
+ # This specification does not dictate what the contents of these
389
+ # items should be. However, the following guidelines are suggested:
390
+ #
391
+ # When CS_CoordinateSystemAuthorityFactory is used to create an
392
+ # object, the "Authority" and "AuthorityCode" values should be set
393
+ # to the authority name of the factory object, and the authority
394
+ # code supplied by the client, respectively. The other values may or
395
+ # may not be set. (If the authority is EPSG, the implementer may
396
+ # consider using the corresponding metadata values in the EPSG
397
+ # tables.)
398
+ #
399
+ # When CS_CoordinateSystemFactory creates an object, the "Name"
400
+ # should be set to the value supplied by the client. All of the
401
+ # other metadata items should be left empty.
402
+ #
403
+ # == Notes
404
+ #
405
+ # This is a non-instantiable abstract class.
406
+ #
407
+ # Most subclasses will have a set of optional parameters in their
408
+ # "create" method to set the metadata fields. These parameters are,
409
+ # in order:
410
+ #
411
+ # * <b>authority</b>: authority name
412
+ # * <b>authority_code</b>: authority-specific identification code
413
+ # * <b>abbreviation</b>: an abbreviation
414
+ # * <b>alias</b>: an alias
415
+ # * <b>remarks</b>: provider-supplied remarks.
416
+ # * <b>extensions</b>: a hash of extension keys and values
417
+
418
+ class Info < Base
419
+ def initialize(name_, authority_ = nil, authority_code_ = nil, abbreviation_ = nil, alias_ = nil, remarks_ = nil, extensions_ = nil) # :nodoc:
420
+ @name = name_
421
+ @authority = authority_ ? authority_.to_s : nil
422
+ @authority_code = authority_code_ ? authority_code_.to_s : nil
423
+ @abbreviation = abbreviation_ ? abbreviation_.to_s : nil
424
+ @alias = alias_ ? alias_.to_s : nil
425
+ @remarks = remarks_ ? remarks_.to_s : nil
426
+ @extensions = {}
427
+ if extensions_
428
+ extensions_.each { |k_, v_| @extensions[k_.to_s] = v_.to_s }
429
+ end
430
+ end
431
+
432
+ # Gets the abbreviation.
433
+ attr_reader :abbreviation
434
+
435
+ # Gets the alias.
436
+ attr_reader :alias
437
+
438
+ # Gets the authority name.
439
+ # An Authority is an organization that maintains definitions of
440
+ # Authority Codes. For example the European Petroleum Survey Group
441
+ # (EPSG) maintains a database of coordinate systems, and other
442
+ # spatial referencing objects, where each object has a code number
443
+ # ID. For example, the EPSG code for a WGS84 Lat/Lon coordinate
444
+ # system is "4326".
445
+ attr_reader :authority
446
+
447
+ # Gets the authority-specific identification code.
448
+ # The AuthorityCode is a compact string defined by an Authority to
449
+ # reference a particular spatial reference object. For example,
450
+ # the European Survey Group (EPSG) authority uses 32 bit integers
451
+ # to reference coordinate systems, so all their code strings will
452
+ # consist of a few digits. The EPSG code for WGS84 Lat/Lon is
453
+ # "4326".
454
+ attr_reader :authority_code
455
+
456
+ # Gets the name.
457
+ attr_reader :name
458
+
459
+ # Gets the provider-supplied remarks.
460
+ attr_reader :remarks
461
+
462
+ # Gets the value of a keyed extension.
463
+ # This is not part of the OGC spec, but it is supported because
464
+ # some coordinate system databases (such as the spatial_ref_sys
465
+ # table for PostGIS 2.0) include it.
466
+ def extension(key_)
467
+ @extensions[key_.to_s]
468
+ end
469
+ end
470
+
471
+ # == OGC spec description
472
+ #
473
+ # Base interface for defining units.
474
+ #
475
+ # == Notes
476
+ #
477
+ # Normally, you will instantiate one of the subclasses LinearUnit or
478
+ # AngularUnit. However, it is possible to instantiate Unit if it is
479
+ # not clear whether the data refers to a LinearUnit or AngularUnit.
480
+
481
+ class Unit < Info
482
+ def initialize(name_, conversion_factor_, *optional_) # :nodoc:
483
+ super(name_, *optional_)
484
+ @conversion_factor = conversion_factor_.to_f
485
+ end
486
+
487
+ # This field is not part of the OGC CT spec, but is part of the
488
+ # SFS. It is an alias of the appropriate field in the subclass,
489
+ # i.e. LinearUnit#meters_per_unit or AngularUnit#radians_per_unit.
490
+ attr_reader :conversion_factor
491
+
492
+ def _wkt_typename # :nodoc:
493
+ "UNIT"
494
+ end
495
+
496
+ def _wkt_content(_open_, _close_) # :nodoc:
497
+ [@conversion_factor]
498
+ end
499
+
500
+ class << self
501
+ # Create a bare Unit that does not specify whether it is a
502
+ # LinearUnit or an AngularUnit, given a unit name and a
503
+ # conversion factor. You may also provide the optional
504
+ # parameters specified by the Info interface.
505
+
506
+ def create(name_, conversion_factor_, *optional_)
507
+ new(name_, conversion_factor_, *optional_)
508
+ end
509
+ end
510
+ end
511
+
512
+ # == OGC spec description
513
+ #
514
+ # Definition of linear units.
515
+
516
+ class LinearUnit < Unit
517
+ # Returns the number of meters per LinearUnit.
518
+ # Also available as Unit#conversion_factor.
519
+
520
+ def meters_per_unit
521
+ @conversion_factor
522
+ end
523
+
524
+ class << self
525
+ # Create a LinearUnit given a unit name and a conversion factor
526
+ # in meters per unit. You may also provide the optional
527
+ # parameters specified by the Info interface.
528
+
529
+ def create(name_, meters_per_unit_, *optional_)
530
+ new(name_, meters_per_unit_, *optional_)
531
+ end
532
+ end
533
+ end
534
+
535
+ # == OGC spec description
536
+ #
537
+ # Definition of angular units.
538
+
539
+ class AngularUnit < Unit
540
+ # Returns the number of radians per AngularUnit.
541
+ # Also available as Unit#conversion_factor.
542
+
543
+ def radians_per_unit
544
+ @conversion_factor
545
+ end
546
+
547
+ class << self
548
+ # Create an AngularUnit given a unit name and a conversion
549
+ # factor in radians per unit. You may also provide the optional
550
+ # parameters specified by the Info interface.
551
+
552
+ def create(name_, radians_per_unit_, *optional_)
553
+ new(name_, radians_per_unit_, *optional_)
554
+ end
555
+ end
556
+ end
557
+
558
+ # == OGC spec description
559
+ #
560
+ # A meridian used to take longitude measurements from.
561
+
562
+ class PrimeMeridian < Info
563
+ def initialize(name_, angular_unit_, longitude_, *optional_) # :nodoc:
564
+ super(name_, *optional_)
565
+ @angular_unit = angular_unit_
566
+ @longitude = longitude_.to_f
567
+ end
568
+
569
+ # Returns the AngularUnits.
570
+ attr_reader :angular_unit
571
+
572
+ # Returns the longitude value relative to the Greenwich Meridian.
573
+ # The longitude is expressed in this objects angular units.
574
+ attr_reader :longitude
575
+
576
+ def _wkt_typename # :nodoc:
577
+ "PRIMEM"
578
+ end
579
+
580
+ def _wkt_content(_open_, _close_) # :nodoc:
581
+ [@longitude]
582
+ end
583
+
584
+ class << self
585
+ # Create a PrimeMeridian given a name, AngularUnits, and the
586
+ # longitude relative to the Greenwich Meridian, expressed in
587
+ # the AngularUnits. You may also provide the optional parameters
588
+ # specified by the Info interface.
589
+
590
+ def create(name_, angular_unit_, longitude_, *optional_)
591
+ new(name_, angular_unit_, longitude_, *optional_)
592
+ end
593
+ end
594
+ end
595
+
596
+ # == OGC spec description
597
+ #
598
+ # An approximation of the Earth's surface as a squashed sphere.
599
+
600
+ class Ellipsoid < Info
601
+ def initialize(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_) # :nodoc:
602
+ super(name_, *optional_)
603
+ @semi_major_axis = semi_major_axis_.to_f
604
+ @semi_minor_axis = semi_minor_axis_.to_f
605
+ @inverse_flattening = inverse_flattening_.to_f
606
+ @ivf_definitive = ivf_definitive_ ? true : false
607
+ @linear_unit = linear_unit_
608
+ end
609
+
610
+ # Gets the equatorial radius. The returned length is expressed in
611
+ # this object's axis units.
612
+ attr_reader :semi_major_axis
613
+
614
+ # Gets the polar radius. The returned length is expressed in this
615
+ # object's axis units.
616
+ attr_reader :semi_minor_axis
617
+
618
+ # Returns the value of the inverse of the flattening constant. The
619
+ # inverse flattening is related to the equatorial/polar radius by
620
+ # the formula ivf=re/(re-rp). For perfect spheres, this formula
621
+ # breaks down, and a special IVF value of zero is used.
622
+ attr_reader :inverse_flattening
623
+
624
+ # Is the Inverse Flattening definitive for this ellipsoid? Some
625
+ # ellipsoids use the IVF as the defining value, and calculate the
626
+ # polar radius whenever asked. Other ellipsoids use the polar
627
+ # radius to calculate the IVF whenever asked. This distinction can
628
+ # be important to avoid floating-point rounding errors.
629
+ attr_reader :ivf_definitive
630
+
631
+ # Returns the LinearUnit. The units of the semi-major and
632
+ # semi-minor axis values.
633
+ attr_reader :axis_unit
634
+
635
+ def _wkt_typename # :nodoc:
636
+ "SPHEROID"
637
+ end
638
+
639
+ def _wkt_content(_open_, _close_) # :nodoc:
640
+ [@semi_major_axis, @inverse_flattening]
641
+ end
642
+
643
+ class << self
644
+ # Create an Ellipsoid given a name, semi-major and semi-minor
645
+ # axes, the inverse flattening, a boolean indicating whether
646
+ # the inverse flattening is definitive, and the LinearUnit
647
+ # indicating the axis units. The LinearUnit is optional and
648
+ # may be set to nil. You may also provide the optional parameters
649
+ # specified by the Info interface.
650
+
651
+ def create(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
652
+ new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, ivf_definitive_, linear_unit_, *optional_)
653
+ end
654
+
655
+ # Create an Ellipsoid given a name, semi-major and semi-minor
656
+ # axes, and the LinearUnit indicating the axis units. In the
657
+ # resulting ellipsoid, the inverse flattening is not definitive.
658
+ # The LinearUnit is optional and may be set to nil. You may also
659
+ # provide the optional parameters specified by the Info interface.
660
+
661
+ def create_ellipsoid(name_, semi_major_axis_, semi_minor_axis_, linear_unit_, *optional_)
662
+ semi_major_axis_ = semi_major_axis_.to_f
663
+ semi_minor_axis_ = semi_minor_axis_.to_f
664
+ inverse_flattening_ = semi_major_axis_ / (semi_major_axis_ - semi_minor_axis_)
665
+ inverse_flattening_ = 0.0 if inverse_flattening_.infinite?
666
+ new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, false, linear_unit_, *optional_)
667
+ end
668
+
669
+ # Create an Ellipsoid given a name, semi-major axis, inverse
670
+ # flattening, and the LinearUnit indicating the axis units. In
671
+ # the resulting ellipsoid, the inverse flattening is definitive.
672
+ # The LinearUnit is optional and may be set to nil. You may also
673
+ # provide the optional parameters specified by the Info interface.
674
+
675
+ def create_flattened_sphere(name_, semi_major_axis_, inverse_flattening_, linear_unit_, *optional_)
676
+ semi_major_axis_ = semi_major_axis_.to_f
677
+ inverse_flattening_ = inverse_flattening_.to_f
678
+ semi_minor_axis_ = semi_major_axis_ - semi_major_axis_ / inverse_flattening_
679
+ semi_minor_axis_ = semi_major_axis_ if semi_minor_axis_.infinite?
680
+ new(name_, semi_major_axis_, semi_minor_axis_, inverse_flattening_, true, linear_unit_, *optional_)
681
+ end
682
+ end
683
+ end
684
+
685
+ # == OGC spec description
686
+ #
687
+ # A set of quantities from which other quantities are calculated.
688
+ # For the OGC abstract model, it can be defined as a set of real
689
+ # points on the earth that have coordinates. EG. A datum can be
690
+ # thought of as a set of parameters defining completely the origin
691
+ # and orientation of a coordinate system with respect to the earth.
692
+ # A textual description and/or a set of parameters describing the
693
+ # relationship of a coordinate system to some predefined physical
694
+ # locations (such as center of mass) and physical directions (such
695
+ # as axis of spin). The definition of the datum may also include
696
+ # the temporal behavior (such as the rate of change of the
697
+ # orientation of the coordinate axes).
698
+ #
699
+ # == Notes
700
+ #
701
+ # This is a non-instantiable abstract class. You must instantiate
702
+ # one of the subclasses HorizontalDatum, VerticalDatum, or
703
+ # LocalDatum.
704
+
705
+ class Datum < Info
706
+ def initialize(name_, datum_type_, *optional_) # :nodoc:
707
+ super(name_, *optional_)
708
+ @datum_type = datum_type_.to_i
709
+ end
710
+
711
+ # Gets the type of the datum as an enumerated code.
712
+ attr_reader :datum_type
713
+
714
+ def _wkt_content(_open_, _close_) # :nodoc:
715
+ []
716
+ end
717
+ end
718
+
719
+ # == OGC spec description
720
+ #
721
+ # Procedure used to measure vertical distances.
722
+
723
+ class VerticalDatum < Datum
724
+ def _wkt_typename # :nodoc:
725
+ "VERT_DATUM"
726
+ end
727
+
728
+ def _wkt_content(_open_, _close_) # :nodoc:
729
+ [@datum_type]
730
+ end
731
+
732
+ class << self
733
+ # Create a VerticalDatum given a name and a datum type code.
734
+ # You may also provide the optional parameters specified by the
735
+ # Info interface.
736
+
737
+ def create(name_, datum_type_, *optional_)
738
+ new(name_, datum_type_, *optional_)
739
+ end
740
+ end
741
+ end
742
+
743
+ # == OGC spec description
744
+ #
745
+ # Local datum. If two local datum objects have the same datum type
746
+ # and name, then they can be considered equal. This means that
747
+ # coordinates can be transformed between two different local
748
+ # coordinate systems, as long as they are based on the same local
749
+ # datum.
750
+
751
+ class LocalDatum < Datum
752
+ def _wkt_typename # :nodoc:
753
+ "LOCAL_DATUM"
754
+ end
755
+
756
+ def _wkt_content(_open_, _close_) # :nodoc:
757
+ [@datum_type]
758
+ end
759
+
760
+ class << self
761
+ # Create a LocalDatum given a name and a datum type code. You
762
+ # may also provide the optional parameters specified by the
763
+ # Info interface.
764
+
765
+ def create(name_, datum_type_, *optional_)
766
+ new(name_, datum_type_, *optional_)
767
+ end
768
+ end
769
+ end
770
+
771
+ # == OGC spec description
772
+ #
773
+ # Procedure used to measure positions on the surface of the Earth.
774
+
775
+ class HorizontalDatum < Datum
776
+ def initialize(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_) # :nodoc:
777
+ super(name_, datum_type_, *optional_)
778
+ @ellipsoid = ellipsoid_
779
+ @wgs84_parameters = wgs84_parameters_
780
+ end
781
+
782
+ # Returns the Ellipsoid.
783
+ attr_reader :ellipsoid
784
+
785
+ # Gets preferred parameters for a Bursa Wolf transformation into
786
+ # WGS84. The 7 returned values correspond to (dx,dy,dz) in meters,
787
+ # (ex,ey,ez) in arc-seconds, and scaling in parts-per-million.
788
+ attr_reader :wgs84_parameters
789
+
790
+ def _wkt_typename # :nodoc:
791
+ "DATUM"
792
+ end
793
+
794
+ def _wkt_content(open_, close_) # :nodoc:
795
+ array_ = [@ellipsoid._to_wkt(open_, close_)]
796
+ array_ << @wgs84_parameters._to_wkt(open_, close_) if @wgs84_parameters
797
+ array_
798
+ end
799
+
800
+ class << self
801
+ # Create a HorizontalDatum given a name, datum type code,
802
+ # Ellipsoid, and WGS84ConversionInfo. The WGS84ConversionInfo
803
+ # is optional and may be set to nil. You may also provide the
804
+ # optional parameters specified by the Info interface.
805
+
806
+ def create(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
807
+ new(name_, datum_type_, ellipsoid_, wgs84_parameters_, *optional_)
808
+ end
809
+ end
810
+ end
811
+
812
+ # == OGC spec description
813
+ #
814
+ # A projection from geographic coordinates to projected coordinates.
815
+
816
+ class Projection < Info
817
+ def initialize(name_, class_name_, parameters_, *optional_) # :nodoc:
818
+ super(name_, *optional_)
819
+ @class_name = class_name_.to_s
820
+ @parameters = parameters_ ? parameters_.dup : []
821
+ end
822
+
823
+ # Gets the projection classification name
824
+ # (e.g. "Transverse_Mercator").
825
+ attr_reader :class_name
826
+
827
+ # Gets number of parameters of the projection.
828
+
829
+ def num_parameters
830
+ @parameters.size
831
+ end
832
+
833
+ # Gets an inexed parameter of the projection.
834
+
835
+ def get_parameter(index_)
836
+ @parameters[index_]
837
+ end
838
+
839
+ # Iterates over the parameters of the projection.
840
+
841
+ def each_parameter(&block_)
842
+ @parameters.each(&block_)
843
+ end
844
+
845
+ def _wkt_typename # :nodoc:
846
+ "PROJECTION"
847
+ end
848
+
849
+ def _wkt_content(_open_, _close_) # :nodoc:
850
+ []
851
+ end
852
+
853
+ class << self
854
+ # Create a Projection given a name, a projection class, and an
855
+ # array of ProjectionParameter. You may also provide the
856
+ # optional parameters specified by the Info interface.
857
+
858
+ def create(name_, class_name_, parameters_, *optional_)
859
+ new(name_, class_name_, parameters_, *optional_)
860
+ end
861
+ end
862
+ end
863
+
864
+ # == OGC spec description
865
+ #
866
+ # Base interface for all coordinate systems.
867
+ #
868
+ # A coordinate system is a mathematical space, where the elements
869
+ # of the space are called positions. Each position is described by
870
+ # a list of numbers. The length of the list corresponds to the
871
+ # dimension of the coordinate system. So in a 2D coordinate system
872
+ # each position is described by a list containing 2 numbers.
873
+ #
874
+ # However, in a coordinate system, not all lists of numbers
875
+ # correspond to a position -- some lists may be outside the domain
876
+ # of the coordinate system. For example, in a 2D Lat/Lon coordinate
877
+ # system, the list (91,91) does not correspond to a position.
878
+ #
879
+ # Some coordinate systems also have a mapping from the mathematical
880
+ # space into locations in the real world. So in a Lat/Lon coordinate
881
+ # system, the mathematical position (lat, long) corresponds to a
882
+ # location on the surface of the Earth. This mapping from the
883
+ # mathematical space into real-world locations is called a Datum.
884
+ #
885
+ # == Notes
886
+ #
887
+ # This is a non-instantiable abstract class. You must instantiate
888
+ # one of the subclasses GeocentricCoordinateSystem,
889
+ # GeographicCoordinateSystem, ProjectedCoordinateSystem,
890
+ # VerticalCoordinateSystem, LocalCoordinateSystem, or
891
+ # CompoundCoordinateSystem.
892
+
893
+ class CoordinateSystem < Info
894
+ def initialize(name_, dimension_, *optional_) # :nodoc:
895
+ super(name_, *optional_)
896
+ @dimension = dimension_.to_i
897
+ end
898
+
899
+ # Dimension of the coordinate system
900
+ attr_reader :dimension
901
+
902
+ # Gets axis details for dimension within coordinate system. Each
903
+ # dimension in the coordinate system has a corresponding axis.
904
+
905
+ def get_axis(_dimension_)
906
+ nil
907
+ end
908
+
909
+ # Gets units for dimension within coordinate system. Each
910
+ # dimension in the coordinate system has corresponding units.
911
+
912
+ def get_units(_dimension_)
913
+ nil
914
+ end
915
+ end
916
+
917
+ # == OGC spec description
918
+ #
919
+ # An aggregate of two coordinate systems (CRS). One of these is
920
+ # usually a CRS based on a two dimensional coordinate system such
921
+ # as a geographic or a projected coordinate system with a horizontal
922
+ # datum. The other is a vertical CRS which is a one-dimensional
923
+ # coordinate system with a vertical datum.
924
+
925
+ class CompoundCoordinateSystem < CoordinateSystem
926
+ def initialize(name_, head_, tail_, *optional_) # :nodoc:
927
+ super(name_, head_.dimension + tail_.dimension, *optional_)
928
+ @head = head_
929
+ @tail = tail_
930
+ end
931
+
932
+ # Gets first sub-coordinate system.
933
+ attr_reader :head
934
+
935
+ # Gets second sub-coordinate system.
936
+ attr_reader :tail
937
+
938
+ # Implements CoordinateSystem#get_axis
939
+
940
+ def get_axis(index_)
941
+ hd_ = @head.dimension
942
+ index_ < hd_ ? @head.get_axis(index_) : @tail.get_axis(index_ - hd_)
943
+ end
944
+
945
+ # Implements CoordinateSystem#get_units
946
+
947
+ def get_units(index_)
948
+ hd_ = @head.dimension
949
+ index_ < hd_ ? @head.get_units(index_) : @tail.get_units(index_ - hd_)
950
+ end
951
+
952
+ def _wkt_typename # :nodoc:
953
+ "COMPD_CS"
954
+ end
955
+
956
+ def _wkt_content(open_, close_) # :nodoc:
957
+ [@head._to_wkt(open_, close_), @tail._to_wkt(open_, close_)]
958
+ end
959
+
960
+ class << self
961
+ # Create a CompoundCoordinateSystem given two sub-coordinate
962
+ # systems. You may also provide the optional parameters
963
+ # specified by the Info interface.
964
+
965
+ def create(name_, head_, tail_, *optional_)
966
+ new(name_, head_, tail_, *optional_)
967
+ end
968
+ end
969
+ end
970
+
971
+ # == OGC spec description
972
+ #
973
+ # A local coordinate system, with uncertain relationship to the
974
+ # world. In general, a local coordinate system cannot be related to
975
+ # other coordinate systems. However, if two objects supporting this
976
+ # interface have the same dimension, axes, units and datum then
977
+ # client code is permitted to assume that the two coordinate systems
978
+ # are identical. This allows several datasets from a common source
979
+ # (e.g. a CAD system) to be overlaid. In addition, some
980
+ # implementations of the Coordinate Transformation (CT) package may
981
+ # have a mechanism for correlating local datums. (E.g. from a
982
+ # database of transformations, which is created and maintained from
983
+ # real-world measurements.)
984
+ #
985
+ # == Notes
986
+ #
987
+ # RGeo's implementation does not provide the Coordinate
988
+ # Transformation (CT) package.
989
+
990
+ class LocalCoordinateSystem < CoordinateSystem
991
+ def initialize(name_, local_datum_, unit_, axes_, *optional_) # :nodoc:
992
+ super(name_, axes_.size, *optional_)
993
+ @local_datum = local_datum_
994
+ @unit = unit_
995
+ @axes = axes_.dup
996
+ end
997
+
998
+ # Gets the local datum.
999
+ attr_reader :local_datum
1000
+
1001
+ # Implements CoordinateSystem#get_axis
1002
+
1003
+ def get_axis(index_)
1004
+ @axes[index_]
1005
+ end
1006
+
1007
+ # Implements CoordinateSystem#get_units
1008
+
1009
+ def get_units(_index_)
1010
+ @unit
1011
+ end
1012
+
1013
+ def _wkt_typename # :nodoc:
1014
+ "LOCAL_CS"
1015
+ end
1016
+
1017
+ def _wkt_content(open_, close_) # :nodoc:
1018
+ [@local_datum._to_wkt(open_, close_), @unit._to_wkt(open_, close_)] + @axes.map { |ax_| ax_._to_wkt(open_, close_) }
1019
+ end
1020
+
1021
+ class << self
1022
+ # Create a LocalCoordinateSystem given a name, a LocalDatum, a
1023
+ # Unit, and an array of at least one AxisInfo. You may also
1024
+ # provide the optional parameters specified by the Info
1025
+ # interface.
1026
+
1027
+ def create(name_, local_datum_, unit_, axes_, *optional_)
1028
+ new(name_, local_datum_, unit_, axes_, *optional_)
1029
+ end
1030
+ end
1031
+ end
1032
+
1033
+ # == OGC spec description
1034
+ #
1035
+ # A 3D coordinate system, with its origin at the centre of the
1036
+ # Earth. The X axis points towards the prime meridian. The Y axis
1037
+ # points East or West. The Z axis points North or South. By default
1038
+ # the Z axis will point North, and the Y axis will point East (e.g.
1039
+ # a right handed system), but you should check the axes for
1040
+ # non-default values.
1041
+
1042
+ class GeocentricCoordinateSystem < CoordinateSystem
1043
+ def initialize(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_) # :nodoc:
1044
+ super(name_, 3, *optional_)
1045
+ @horizontal_datum = horizontal_datum_
1046
+ @prime_meridian = prime_meridian_
1047
+ @linear_unit = linear_unit_
1048
+ @axis0 = axis0_
1049
+ @axis1 = axis1_
1050
+ @axis2 = axis2_
1051
+ end
1052
+
1053
+ # Returns the HorizontalDatum. The horizontal datum is used to
1054
+ # determine where the centre of the Earth is considered to be.
1055
+ # All coordinate points will be measured from the centre of the
1056
+ # Earth, and not the surface.
1057
+ attr_reader :horizontal_datum
1058
+
1059
+ # Returns the PrimeMeridian.
1060
+ attr_reader :prime_meridian
1061
+
1062
+ # Gets the units used along all the axes.
1063
+ attr_reader :linear_unit
1064
+
1065
+ # Implements CoordinateSystem#get_units
1066
+
1067
+ def get_units(_index_)
1068
+ @linear_unit
1069
+ end
1070
+
1071
+ # Implements CoordinateSystem#get_axis
1072
+
1073
+ def get_axis(index_)
1074
+ [@axis0, @axis1, @axis2][index_]
1075
+ end
1076
+
1077
+ def _wkt_typename # :nodoc:
1078
+ "GEOCCS"
1079
+ end
1080
+
1081
+ def _wkt_content(open_, close_) # :nodoc:
1082
+ arr_ = [@horizontal_datum._to_wkt(open_, close_), @prime_meridian._to_wkt(open_, close_), @linear_unit._to_wkt(open_, close_)]
1083
+ arr_ << @axis0._to_wkt(open_, close_) if @axis0
1084
+ arr_ << @axis1._to_wkt(open_, close_) if @axis1
1085
+ arr_ << @axis2._to_wkt(open_, close_) if @axis2
1086
+ arr_
1087
+ end
1088
+
1089
+ class << self
1090
+ # Create a GeocentricCoordinateSystem given a name, a
1091
+ # HorizontalDatum, a PrimeMeridian, a LinearUnit, and three
1092
+ # AxisInfo objects. The AxisInfo are optional and may be nil.
1093
+ # You may also provide the optional parameters specified by the
1094
+ # Info interface.
1095
+
1096
+ def create(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
1097
+ new(name_, horizontal_datum_, prime_meridian_, linear_unit_, axis0_, axis1_, axis2_, *optional_)
1098
+ end
1099
+ end
1100
+ end
1101
+
1102
+ # == OGC spec description
1103
+ #
1104
+ # A one-dimensional coordinate system suitable for vertical
1105
+ # measurements.
1106
+
1107
+ class VerticalCoordinateSystem < CoordinateSystem
1108
+ def initialize(name_, vertical_datum_, vertical_unit_, axis_, *optional_) # :nodoc:
1109
+ super(name_, 1, *optional_)
1110
+ @vertical_datum = vertical_datum_
1111
+ @vertical_unit = vertical_unit_
1112
+ @axis = axis_
1113
+ end
1114
+
1115
+ # Gets the vertical datum, which indicates the measurement method.
1116
+ attr_reader :vertical_datum
1117
+
1118
+ # Gets the units used along the vertical axis. The vertical units
1119
+ # must be the same as the CS_CoordinateSystem units.
1120
+ attr_reader :vertical_unit
1121
+
1122
+ # Implements CoordinateSystem#get_units
1123
+
1124
+ def get_units(_index_)
1125
+ @vertical_unit
1126
+ end
1127
+
1128
+ # Implements CoordinateSystem#get_axis
1129
+
1130
+ def get_axis(_index_)
1131
+ @axis
1132
+ end
1133
+
1134
+ def _wkt_typename # :nodoc:
1135
+ "VERT_CS"
1136
+ end
1137
+
1138
+ def _wkt_content(open_, close_) # :nodoc:
1139
+ arr_ = [@vertical_datum._to_wkt(open_, close_), @vertical_unit._to_wkt(open_, close_)]
1140
+ arr_ << @axis._to_wkt(open_, close_) if @axis
1141
+ arr_
1142
+ end
1143
+
1144
+ class << self
1145
+ # Create a VerticalCoordinateSystem given a name, a
1146
+ # VerticalDatum, a LinearUnit, and an AxisInfo. The AxisInfo is
1147
+ # optional and may be nil. You may also provide the optional
1148
+ # parameters specified by the Info interface.
1149
+
1150
+ def create(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
1151
+ new(name_, vertical_datum_, vertical_unit_, axis_, *optional_)
1152
+ end
1153
+ end
1154
+ end
1155
+
1156
+ # == OGC spec description
1157
+ #
1158
+ # A 2D coordinate system suitable for positions on the Earth's surface.
1159
+ #
1160
+ # == Notes
1161
+ #
1162
+ # This is a non-instantiable abstract class. You must instantiate
1163
+ # one of the subclasses GeographicCoordinateSystem or
1164
+ # ProjectedCoordinateSystem.
1165
+
1166
+ class HorizontalCoordinateSystem < CoordinateSystem
1167
+ def initialize(name_, horizontal_datum_, *optional_) # :nodoc:
1168
+ super(name_, 2, *optional_)
1169
+ @horizontal_datum = horizontal_datum_
1170
+ end
1171
+
1172
+ # Returns the HorizontalDatum.
1173
+ attr_reader :horizontal_datum
1174
+ end
1175
+
1176
+ # == OGC spec description
1177
+ #
1178
+ # A coordinate system based on latitude and longitude. Some
1179
+ # geographic coordinate systems are Lat/Lon, and some are Lon/Lat.
1180
+ # You can find out which this is by examining the axes. You should
1181
+ # also check the angular units, since not all geographic coordinate
1182
+ # systems use degrees.
1183
+
1184
+ class GeographicCoordinateSystem < HorizontalCoordinateSystem
1185
+ def initialize(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_) # :nodoc:
1186
+ super(name_, horizontal_datum_, *optional_)
1187
+ @prime_meridian = prime_meridian_
1188
+ @angular_unit = angular_unit_
1189
+ @axis0 = axis0_
1190
+ @axis1 = axis1_
1191
+ end
1192
+
1193
+ # Returns the PrimeMeridian.
1194
+ attr_reader :prime_meridian
1195
+
1196
+ # Returns the AngularUnit. The angular unit must be the same as
1197
+ # the CS_CoordinateSystem units.
1198
+ attr_reader :angular_unit
1199
+
1200
+ # Implements CoordinateSystem#get_units
1201
+
1202
+ def get_units(_index_)
1203
+ @angular_unit
1204
+ end
1205
+
1206
+ # Implements CoordinateSystem#get_axis
1207
+
1208
+ def get_axis(index_)
1209
+ index_ == 1 ? @axis1 : @axis0
1210
+ end
1211
+
1212
+ # Gets the number of available conversions to WGS84 coordinates.
1213
+
1214
+ def num_conversion_to_wgs84
1215
+ @horizontal_datum.wgs84_parameters ? 1 : 0
1216
+ end
1217
+
1218
+ # Gets details on a conversion to WGS84. Some geographic
1219
+ # coordinate systems provide several transformations into WGS84,
1220
+ # which are designed to provide good accuracy in different areas
1221
+ # of interest. The first conversion (with index=0) should provide
1222
+ # acceptable accuracy over the largest possible area of interest.
1223
+
1224
+ def get_wgs84_conversion_info(_index_)
1225
+ @horizontal_datum.wgs84_parameters
1226
+ end
1227
+
1228
+ def _wkt_typename # :nodoc:
1229
+ "GEOGCS"
1230
+ end
1231
+
1232
+ def _wkt_content(open_, close_) # :nodoc:
1233
+ arr_ = [@horizontal_datum._to_wkt(open_, close_), @prime_meridian._to_wkt(open_, close_), @angular_unit._to_wkt(open_, close_)]
1234
+ arr_ << @axis0._to_wkt(open_, close_) if @axis0
1235
+ arr_ << @axis1._to_wkt(open_, close_) if @axis1
1236
+ arr_
1237
+ end
1238
+
1239
+ class << self
1240
+ # Create a GeographicCoordinateSystem, given a name, an
1241
+ # AngularUnit, a HorizontalDatum, a PrimeMeridian, and two
1242
+ # AxisInfo objects. The AxisInfo objects are optional and may
1243
+ # be set to nil. You may also provide the optional parameters
1244
+ # specified by the Info interface.
1245
+
1246
+ def create(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
1247
+ new(name_, angular_unit_, horizontal_datum_, prime_meridian_, axis0_, axis1_, *optional_)
1248
+ end
1249
+ end
1250
+ end
1251
+
1252
+ # == OGC spec description
1253
+ #
1254
+ # A 2D cartographic coordinate system.
1255
+
1256
+ class ProjectedCoordinateSystem < HorizontalCoordinateSystem
1257
+ def initialize(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_) # :nodoc:
1258
+ super(name_, geographic_coordinate_system_.horizontal_datum, *optional_)
1259
+ @geographic_coordinate_system = geographic_coordinate_system_
1260
+ @projection = projection_
1261
+ @linear_unit = linear_unit_
1262
+ @axis0 = axis0_
1263
+ @axis1 = axis1_
1264
+ end
1265
+
1266
+ # Returns the GeographicCoordinateSystem.
1267
+ attr_reader :geographic_coordinate_system
1268
+
1269
+ # Gets the projection.
1270
+ attr_reader :projection
1271
+
1272
+ # Returns the LinearUnits. The linear unit must be the same as
1273
+ # the CS_CoordinateSystem units.
1274
+ attr_reader :linear_unit
1275
+
1276
+ # Implements CoordinateSystem#get_units
1277
+
1278
+ def get_units(_index_)
1279
+ @linear_unit
1280
+ end
1281
+
1282
+ # Implements CoordinateSystem#get_axis
1283
+
1284
+ def get_axis(index_)
1285
+ index_ == 1 ? @axis1 : @axis0
1286
+ end
1287
+
1288
+ def _wkt_typename # :nodoc:
1289
+ "PROJCS"
1290
+ end
1291
+
1292
+ def _wkt_content(open_, close_) # :nodoc:
1293
+ arr_ = [@geographic_coordinate_system._to_wkt(open_, close_), @projection._to_wkt(open_, close_)]
1294
+ @projection.each_parameter { |param_| arr_ << param_._to_wkt(open_, close_) }
1295
+ arr_ << @linear_unit._to_wkt(open_, close_)
1296
+ arr_ << @axis0._to_wkt(open_, close_) if @axis0
1297
+ arr_ << @axis1._to_wkt(open_, close_) if @axis1
1298
+ arr_
1299
+ end
1300
+
1301
+ class << self
1302
+ # Create a ProjectedCoordinateSystem given a name, a
1303
+ # GeographicCoordinateSystem, and Projection, a LinearUnit, and
1304
+ # two AxisInfo objects. The AxisInfo objects are optional and
1305
+ # may be set to nil. You may also provide the optional
1306
+ # parameters specified by the Info interface.
1307
+
1308
+ def create(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
1309
+ new(name_, geographic_coordinate_system_, projection_, linear_unit_, axis0_, axis1_, *optional_)
1310
+ end
1311
+ end
1312
+ end
1313
+ end
1314
+ end
1315
+ end