rgeo-dschee 0.5.4

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.
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