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,110 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Simple mercator projection
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ class SimpleMercatorProjector # :nodoc:
10
+ EQUATORIAL_RADIUS = 6_378_137.0
11
+
12
+ def initialize(geography_factory_, opts_ = {})
13
+ @geography_factory = geography_factory_
14
+ @projection_factory = Cartesian.preferred_factory(srid: 3857,
15
+ proj4: SimpleMercatorProjector._proj4_3857,
16
+ coord_sys: SimpleMercatorProjector._coordsys_3857,
17
+ buffer_resolution: opts_[:buffer_resolution],
18
+ lenient_multi_polygon_assertions: opts_[:lenient_multi_polygon_assertions],
19
+ uses_lenient_assertions: opts_[:uses_lenient_assertions],
20
+ has_z_coordinate: opts_[:has_z_coordinate],
21
+ has_m_coordinate: opts_[:has_m_coordinate])
22
+ end
23
+
24
+ def _set_factories(geography_factory_, projection_factory_) # :nodoc:
25
+ @geography_factory = geography_factory_
26
+ @projection_factory = projection_factory_
27
+ end
28
+
29
+ attr_reader :projection_factory
30
+
31
+ def project(geometry_)
32
+ case geometry_
33
+ when Feature::Point
34
+ rpd_ = ImplHelper::Math::RADIANS_PER_DEGREE
35
+ radius_ = EQUATORIAL_RADIUS
36
+ @projection_factory.point(geometry_.x * rpd_ * radius_,
37
+ ::Math.log(::Math.tan(::Math::PI / 4.0 + geometry_.y * rpd_ / 2.0)) * radius_)
38
+ when Feature::Line
39
+ @projection_factory.line(project(geometry_.start_point), project(geometry_.end_point))
40
+ when Feature::LinearRing
41
+ @projection_factory.linear_ring(geometry_.points.map { |p_| project(p_) })
42
+ when Feature::LineString
43
+ @projection_factory.line_string(geometry_.points.map { |p_| project(p_) })
44
+ when Feature::Polygon
45
+ @projection_factory.polygon(project(geometry_.exterior_ring),
46
+ geometry_.interior_rings.map { |p_| project(p_) })
47
+ when Feature::MultiPoint
48
+ @projection_factory.multi_point(geometry_.map { |p_| project(p_) })
49
+ when Feature::MultiLineString
50
+ @projection_factory.multi_line_string(geometry_.map { |p_| project(p_) })
51
+ when Feature::MultiPolygon
52
+ @projection_factory.multi_polygon(geometry_.map { |p_| project(p_) })
53
+ when Feature::GeometryCollection
54
+ @projection_factory.collection(geometry_.map { |p_| project(p_) })
55
+ end
56
+ end
57
+
58
+ def unproject(geometry_)
59
+ case geometry_
60
+ when Feature::Point
61
+ dpr_ = ImplHelper::Math::DEGREES_PER_RADIAN
62
+ radius_ = EQUATORIAL_RADIUS
63
+ @geography_factory.point(geometry_.x / radius_ * dpr_,
64
+ (2.0 * ::Math.atan(::Math.exp(geometry_.y / radius_)) - ::Math::PI / 2.0) * dpr_)
65
+ when Feature::Line
66
+ @geography_factory.line(unproject(geometry_.start_point), unproject(geometry_.end_point))
67
+ when Feature::LinearRing
68
+ @geography_factory.linear_ring(geometry_.points.map { |p_| unproject(p_) })
69
+ when Feature::LineString
70
+ @geography_factory.line_string(geometry_.points.map { |p_| unproject(p_) })
71
+ when Feature::Polygon
72
+ @geography_factory.polygon(unproject(geometry_.exterior_ring),
73
+ geometry_.interior_rings.map { |p_| unproject(p_) })
74
+ when Feature::MultiPoint
75
+ @geography_factory.multi_point(geometry_.map { |p_| unproject(p_) })
76
+ when Feature::MultiLineString
77
+ @geography_factory.multi_line_string(geometry_.map { |p_| unproject(p_) })
78
+ when Feature::MultiPolygon
79
+ @geography_factory.multi_polygon(geometry_.map { |p_| unproject(p_) })
80
+ when Feature::GeometryCollection
81
+ @geography_factory.collection(geometry_.map { |p_| unproject(p_) })
82
+ end
83
+ end
84
+
85
+ def wraps?
86
+ true
87
+ end
88
+
89
+ def limits_window
90
+ @limits_window ||= ProjectedWindow.new(@geography_factory,
91
+ -20_037_508.342789, -20_037_508.342789, 20_037_508.342789, 20_037_508.342789,
92
+ is_limits: true)
93
+ end
94
+
95
+ def self._proj4_3857 # :nodoc:
96
+ unless defined?(@proj4_3857)
97
+ @proj4_3857 = CoordSys::Proj4.create("+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +a=6378137 +b=6378137 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs")
98
+ end
99
+ @proj4_3857
100
+ end
101
+
102
+ def self._coordsys_3857 # :nodoc:
103
+ unless defined?(@coordsys_3857)
104
+ @coordsys_3857 = CoordSys::CS.create_from_wkt('PROJCS["Popular Visualisation CRS / Mercator",GEOGCS["Popular Visualisation CRS",DATUM["Popular_Visualisation_Datum",SPHEROID["Popular Visualisation Sphere",6378137,0,AUTHORITY["EPSG","7059"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6055"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4055"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],AUTHORITY["EPSG","3785"],AXIS["X",EAST],AXIS["Y",NORTH]]')
105
+ end
106
+ @coordsys_3857
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,100 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Spherical geographic feature classes
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ class SphericalPointImpl # :nodoc:
10
+ include Feature::Point
11
+ include ImplHelper::BasicGeometryMethods
12
+ include ImplHelper::BasicPointMethods
13
+ include SphericalGeometryMethods
14
+ include SphericalPointMethods
15
+
16
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Point).include_in_class(self, true)
17
+ end
18
+
19
+ class SphericalLineStringImpl # :nodoc:
20
+ include Feature::LineString
21
+ include ImplHelper::BasicGeometryMethods
22
+ include ImplHelper::BasicLineStringMethods
23
+ include SphericalGeometryMethods
24
+ include SphericalLineStringMethods
25
+
26
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LineString).include_in_class(self, true)
27
+ end
28
+
29
+ class SphericalLineImpl # :nodoc:
30
+ include Feature::Line
31
+ include ImplHelper::BasicGeometryMethods
32
+ include ImplHelper::BasicLineStringMethods
33
+ include ImplHelper::BasicLineMethods
34
+ include SphericalGeometryMethods
35
+ include SphericalLineStringMethods
36
+
37
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Line).include_in_class(self, true)
38
+ end
39
+
40
+ class SphericalLinearRingImpl # :nodoc:
41
+ include Feature::LinearRing
42
+ include ImplHelper::BasicGeometryMethods
43
+ include ImplHelper::BasicLineStringMethods
44
+ include ImplHelper::BasicLinearRingMethods
45
+ include SphericalGeometryMethods
46
+ include SphericalLineStringMethods
47
+
48
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LinearRing).include_in_class(self, true)
49
+ end
50
+
51
+ class SphericalPolygonImpl # :nodoc:
52
+ include Feature::Polygon
53
+ include ImplHelper::BasicGeometryMethods
54
+ include ImplHelper::BasicPolygonMethods
55
+ include SphericalGeometryMethods
56
+
57
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Polygon).include_in_class(self, true)
58
+ end
59
+
60
+ class SphericalGeometryCollectionImpl # :nodoc:
61
+ include Feature::GeometryCollection
62
+ include ImplHelper::BasicGeometryMethods
63
+ include ImplHelper::BasicGeometryCollectionMethods
64
+ include SphericalGeometryMethods
65
+
66
+ Feature::MixinCollection::GLOBAL.for_type(Feature::GeometryCollection).include_in_class(self, true)
67
+ end
68
+
69
+ class SphericalMultiPointImpl # :nodoc:
70
+ include Feature::MultiPoint
71
+ include ImplHelper::BasicGeometryMethods
72
+ include ImplHelper::BasicGeometryCollectionMethods
73
+ include ImplHelper::BasicMultiPointMethods
74
+ include SphericalGeometryMethods
75
+
76
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPoint).include_in_class(self, true)
77
+ end
78
+
79
+ class SphericalMultiLineStringImpl # :nodoc:
80
+ include Feature::MultiLineString
81
+ include ImplHelper::BasicGeometryMethods
82
+ include ImplHelper::BasicGeometryCollectionMethods
83
+ include ImplHelper::BasicMultiLineStringMethods
84
+ include SphericalGeometryMethods
85
+ include SphericalMultiLineStringMethods
86
+
87
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiLineString).include_in_class(self, true)
88
+ end
89
+
90
+ class SphericalMultiPolygonImpl # :nodoc:
91
+ include Feature::MultiPolygon
92
+ include ImplHelper::BasicGeometryMethods
93
+ include ImplHelper::BasicGeometryCollectionMethods
94
+ include ImplHelper::BasicMultiPolygonMethods
95
+ include SphericalGeometryMethods
96
+
97
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPolygon).include_in_class(self, true)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,134 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Spherical geographic common methods
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ module SphericalGeometryMethods # :nodoc:
10
+ def srid
11
+ factory.srid
12
+ end
13
+ end
14
+
15
+ module SphericalPointMethods # :nodoc:
16
+ def _validate_geometry
17
+ if @x < -180.0 || @x > 180.0
18
+ @x = @x % 360.0
19
+ @x -= 360.0 if @x > 180.0
20
+ end
21
+ @y = 90.0 if @y > 90.0
22
+ @y = -90.0 if @y < -90.0
23
+ super
24
+ end
25
+
26
+ def _xyz
27
+ @xyz ||= SphericalMath::PointXYZ.from_latlon(@y, @x)
28
+ end
29
+
30
+ def distance(rhs_)
31
+ rhs_ = Feature.cast(rhs_, @factory)
32
+ case rhs_
33
+ when SphericalPointImpl
34
+ _xyz.dist_to_point(rhs_._xyz) * SphericalMath::RADIUS
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def equals?(rhs_)
41
+ return false unless rhs_.is_a?(self.class) && rhs_.factory == factory
42
+ case rhs_
43
+ when Feature::Point
44
+ if @y == 90
45
+ rhs_.y == 90
46
+ elsif @y == -90
47
+ rhs_.y == -90
48
+ else
49
+ rhs_.x == @x && rhs_.y == @y
50
+ end
51
+ when Feature::LineString
52
+ rhs_.num_points > 0 && rhs_.points.all? { |elem_| equals?(elem_) }
53
+ when Feature::GeometryCollection
54
+ rhs_.num_geometries > 0 && rhs_.all? { |elem_| equals?(elem_) }
55
+ else
56
+ false
57
+ end
58
+ end
59
+
60
+ def buffer(distance_)
61
+ radius_ = distance_ / SphericalMath::RADIUS
62
+ radius_ = 1.5 if radius_ > 1.5
63
+ cos_ = ::Math.cos(radius_)
64
+ sin_ = ::Math.sin(radius_)
65
+ point_count_ = factory.property(:buffer_resolution) * 4
66
+ p0_ = _xyz
67
+ p1_ = p0_.create_perpendicular
68
+ p2_ = p1_ % p0_
69
+ angle_ = ::Math::PI * 2.0 / point_count_
70
+ points_ = (0...point_count_).map do |i_|
71
+ r_ = angle_ * i_
72
+ pi_ = SphericalMath::PointXYZ.weighted_combination(p1_, ::Math.cos(r_), p2_, ::Math.sin(r_))
73
+ p_ = SphericalMath::PointXYZ.weighted_combination(p0_, cos_, pi_, sin_)
74
+ factory.point(*p_.lonlat)
75
+ end
76
+ factory.polygon(factory.linear_ring(points_))
77
+ end
78
+
79
+ def self.included(klass_)
80
+ klass_.module_eval do
81
+ alias_method :longitude, :x
82
+ alias_method :lon, :x
83
+ alias_method :latitude, :y
84
+ alias_method :lat, :y
85
+ end
86
+ end
87
+ end
88
+
89
+ module SphericalLineStringMethods # :nodoc:
90
+ def _arcs
91
+ unless defined?(@arcs)
92
+ @arcs = (0..num_points - 2).map do |i_|
93
+ SphericalMath::ArcXYZ.new(point_n(i_)._xyz, point_n(i_ + 1)._xyz)
94
+ end
95
+ end
96
+ @arcs
97
+ end
98
+
99
+ def is_simple?
100
+ arcs_ = _arcs
101
+ len_ = arcs_.length
102
+ return false if arcs_.any?(&:degenerate?)
103
+ return true if len_ == 1
104
+ return arcs_[0].s != arcs_[1].e if len_ == 2
105
+ arcs_.each_with_index do |arc_, index_|
106
+ nindex_ = index_ + 1
107
+ nindex_ = nil if nindex_ == len_
108
+ return false if nindex_ && arc_.contains_point?(arcs_[nindex_].e)
109
+ pindex_ = index_ - 1
110
+ pindex_ = nil if pindex_ < 0
111
+ return false if pindex_ && arc_.contains_point?(arcs_[pindex_].s)
112
+ next unless nindex_
113
+ oindex_ = nindex_ + 1
114
+ while oindex_ < len_
115
+ oarc_ = arcs_[oindex_]
116
+ return false if !(index_ == 0 && oindex_ == len_ - 1 && arc_.s == oarc_.e) && arc_.intersects_arc?(oarc_)
117
+ oindex_ += 1
118
+ end
119
+ end
120
+ true
121
+ end
122
+
123
+ def length
124
+ _arcs.inject(0.0) { |sum_, arc_| sum_ + arc_.length } * SphericalMath::RADIUS
125
+ end
126
+ end
127
+
128
+ module SphericalMultiLineStringMethods # :nodoc:
129
+ def length
130
+ inject(0.0) { |sum_, geom_| sum_ + geom_.length }
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,188 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Core calculations on the sphere
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ module SphericalMath # :nodoc:
10
+ RADIUS = 6_378_137.0
11
+
12
+ # Represents a point on the unit sphere in (x,y,z) coordinates
13
+ # instead of lat-lon. This form is often faster, more convenient,
14
+ # and more numerically stable for certain computations.
15
+ #
16
+ # The coordinate system is a right-handed system where the z-axis
17
+ # goes through the north pole, the x-axis goes through the prime
18
+ # meridian, and the y-axis goes through +90 degrees longitude.
19
+ #
20
+ # This object is also used to represent a great circle, as its axis
21
+ # of rotation.
22
+
23
+ class PointXYZ # :nodoc:
24
+ def initialize(x_, y_, z_)
25
+ r_ = ::Math.sqrt(x_ * x_ + y_ * y_ + z_ * z_)
26
+ @x = (x_ / r_).to_f
27
+ @y = (y_ / r_).to_f
28
+ @z = (z_ / r_).to_f
29
+ raise "Not a number" if @x.nan? || @y.nan? || @z.nan?
30
+ end
31
+
32
+ def to_s
33
+ "(#{@x}, #{@y}, #{@z})"
34
+ end
35
+
36
+ attr_reader :x
37
+ attr_reader :y
38
+ attr_reader :z
39
+
40
+ def eql?(rhs_)
41
+ rhs_.is_a?(PointXYZ) && @x == rhs_.x && @y == rhs_.y && @z == rhs_.z
42
+ end
43
+ alias_method :==, :eql?
44
+
45
+ def latlon
46
+ lat_rad_ = ::Math.asin(@z)
47
+ lon_rad_ = begin
48
+ ::Math.atan2(@y, @x)
49
+ rescue
50
+ 0.0
51
+ end
52
+ rpd_ = ImplHelper::Math::RADIANS_PER_DEGREE
53
+ [lat_rad_ / rpd_, lon_rad_ / rpd_]
54
+ end
55
+
56
+ def lonlat
57
+ lat_rad_ = ::Math.asin(@z)
58
+ lon_rad_ = begin
59
+ ::Math.atan2(@y, @x)
60
+ rescue
61
+ 0.0
62
+ end
63
+ rpd_ = ImplHelper::Math::RADIANS_PER_DEGREE
64
+ [lon_rad_ / rpd_, lat_rad_ / rpd_]
65
+ end
66
+
67
+ def *(rhs_)
68
+ val_ = @x * rhs_.x + @y * rhs_.y + @z * rhs_.z
69
+ val_ = 1.0 if val_ > 1.0
70
+ val_ = -1.0 if val_ < -1.0
71
+ val_
72
+ end
73
+
74
+ def %(rhs_)
75
+ rx_ = rhs_.x
76
+ ry_ = rhs_.y
77
+ rz_ = rhs_.z
78
+ begin
79
+ PointXYZ.new(@y * rz_ - @z * ry_, @z * rx_ - @x * rz_, @x * ry_ - @y * rx_)
80
+ rescue
81
+ nil
82
+ end
83
+ end
84
+
85
+ def dist_to_point(rhs_)
86
+ rx_ = rhs_.x
87
+ ry_ = rhs_.y
88
+ rz_ = rhs_.z
89
+ dot_ = @x * rx_ + @y * ry_ + @z * rz_
90
+ if dot_ > -0.8 && dot_ < 0.8
91
+ ::Math.acos(dot_)
92
+ else
93
+ x_ = @y * rz_ - @z * ry_
94
+ y_ = @z * rx_ - @x * rz_
95
+ z_ = @x * ry_ - @y * rx_
96
+ as_ = ::Math.asin(::Math.sqrt(x_ * x_ + y_ * y_ + z_ * z_))
97
+ dot_ > 0.0 ? as_ : ::Math::PI - as_
98
+ end
99
+ end
100
+
101
+ # Creates some point that is perpendicular to this point
102
+
103
+ def create_perpendicular
104
+ p1dot_ = self * P1
105
+ p2dot_ = self * P2
106
+ p1dot_ = -p1dot_ if p1dot_ < 0
107
+ p2dot_ = -p2dot_ if p2dot_ < 0
108
+ p1dot_ < p2dot_ ? (self % P1) : (self % P2)
109
+ end
110
+
111
+ def self.from_latlon(lat_, lon_)
112
+ rpd_ = ImplHelper::Math::RADIANS_PER_DEGREE
113
+ lat_rad_ = rpd_ * lat_
114
+ lon_rad_ = rpd_ * lon_
115
+ z_ = ::Math.sin(lat_rad_)
116
+ r_ = ::Math.cos(lat_rad_)
117
+ x_ = ::Math.cos(lon_rad_) * r_
118
+ y_ = ::Math.sin(lon_rad_) * r_
119
+ new(x_, y_, z_)
120
+ end
121
+
122
+ def self.weighted_combination(p1_, w1_, p2_, w2_)
123
+ new(p1_.x * w1_ + p2_.x * w2_, p1_.y * w1_ + p2_.y * w2_, p1_.z * w1_ + p2_.z * w2_)
124
+ end
125
+
126
+ P1 = new(1, 0, 0)
127
+ P2 = new(0, 1, 0)
128
+ end
129
+
130
+ # Represents a finite arc on the sphere.
131
+
132
+ class ArcXYZ # :nodoc:
133
+ def initialize(start_, end_)
134
+ @s = start_
135
+ @e = end_
136
+ @axis = false
137
+ end
138
+
139
+ attr_reader :s
140
+ attr_reader :e
141
+
142
+ def to_s
143
+ "#{@s} - #{@e}"
144
+ end
145
+
146
+ def eql?(rhs_)
147
+ rhs_.is_a?(ArcXYZ) && @s == rhs_.s && @e == rhs_.e
148
+ end
149
+ alias_method :==, :eql?
150
+
151
+ def degenerate?
152
+ axis_ = axis
153
+ axis_.x == 0 && axis_.y == 0 && axis_.z == 0
154
+ end
155
+
156
+ def axis
157
+ @axis = @s % @e if @axis == false
158
+ @axis
159
+ end
160
+
161
+ def contains_point?(obj_)
162
+ axis_ = axis
163
+ saxis_ = ArcXYZ.new(@s, obj_).axis
164
+ eaxis_ = ArcXYZ.new(obj_, @e).axis
165
+ !saxis_ || !eaxis_ || obj_ * axis_ == 0.0 && saxis_ * axis_ > 0 && eaxis_ * axis_ > 0
166
+ end
167
+
168
+ def intersects_arc?(obj_)
169
+ my_axis_ = axis
170
+ dot1_ = my_axis_ * obj_.s
171
+ dot2_ = my_axis_ * obj_.e
172
+ if dot1_ >= 0.0 && dot2_ <= 0.0 || dot1_ <= 0.0 && dot2_ >= 0.0
173
+ ob_axis_ = obj_.axis
174
+ dot1_ = ob_axis_ * @s
175
+ dot2_ = ob_axis_ * @e
176
+ dot1_ >= 0.0 && dot2_ <= 0.0 || dot1_ <= 0.0 && dot2_ >= 0.0
177
+ else
178
+ false
179
+ end
180
+ end
181
+
182
+ def length
183
+ @s.dist_to_point(@e)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end