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,58 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Proj4 projection
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ class Proj4Projector # :nodoc:
10
+ def initialize(geography_factory_, projection_factory_)
11
+ @geography_factory = geography_factory_
12
+ @projection_factory = projection_factory_
13
+ end
14
+
15
+ def _set_factories(geography_factory_, projection_factory_) # :nodoc:
16
+ @geography_factory = geography_factory_
17
+ @projection_factory = projection_factory_
18
+ end
19
+
20
+ def project(geometry_)
21
+ Feature.cast(geometry_, @projection_factory, :project)
22
+ end
23
+
24
+ def unproject(geometry_)
25
+ Feature.cast(geometry_, @geography_factory, :project)
26
+ end
27
+
28
+ attr_reader :projection_factory
29
+
30
+ def wraps?
31
+ false
32
+ end
33
+
34
+ def limits_window
35
+ nil
36
+ end
37
+
38
+ class << self
39
+ def create_from_existing_factory(geography_factory_, projection_factory_)
40
+ new(geography_factory_, projection_factory_)
41
+ end
42
+
43
+ def create_from_proj4(geography_factory_, proj4_, opts_ = {})
44
+ projection_factory_ = Cartesian.preferred_factory(proj4: proj4_,
45
+ coord_sys: opts_[:coord_sys], srid: opts_[:srid],
46
+ buffer_resolution: opts_[:buffer_resolution],
47
+ lenient_multi_polygon_assertions: opts_[:lenient_multi_polygon_assertions],
48
+ uses_lenient_assertions: opts_[:uses_lenient_assertions],
49
+ has_z_coordinate: opts_[:has_z_coordinate],
50
+ has_m_coordinate: opts_[:has_m_coordinate],
51
+ wkt_parser: opts_[:wkt_parser], wkt_generator: opts_[:wkt_generator],
52
+ wkb_parser: opts_[:wkb_parser], wkb_generator: opts_[:wkb_generator])
53
+ new(geography_factory_, projection_factory_)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,107 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Projtected geographic feature classes
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ class ProjectedPointImpl # :nodoc:
10
+ include Feature::Point
11
+ include ImplHelper::BasicGeometryMethods
12
+ include ImplHelper::BasicPointMethods
13
+ include ProjectedGeometryMethods
14
+ include ProjectedPointMethods
15
+
16
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Point).include_in_class(self, true)
17
+ end
18
+
19
+ class ProjectedLineStringImpl # :nodoc:
20
+ include Feature::LineString
21
+ include ImplHelper::BasicGeometryMethods
22
+ include ImplHelper::BasicLineStringMethods
23
+ include ProjectedGeometryMethods
24
+ include ProjectedNCurveMethods
25
+ include ProjectedLineStringMethods
26
+
27
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LineString).include_in_class(self, true)
28
+ end
29
+
30
+ class ProjectedLinearRingImpl # :nodoc:
31
+ include Feature::LinearRing
32
+ include ImplHelper::BasicGeometryMethods
33
+ include ImplHelper::BasicLineStringMethods
34
+ include ImplHelper::BasicLinearRingMethods
35
+ include ProjectedGeometryMethods
36
+ include ProjectedNCurveMethods
37
+ include ProjectedLineStringMethods
38
+
39
+ Feature::MixinCollection::GLOBAL.for_type(Feature::LinearRing).include_in_class(self, true)
40
+ end
41
+
42
+ class ProjectedLineImpl # :nodoc:
43
+ include Feature::Line
44
+ include ImplHelper::BasicGeometryMethods
45
+ include ImplHelper::BasicLineStringMethods
46
+ include ImplHelper::BasicLineMethods
47
+ include ProjectedGeometryMethods
48
+ include ProjectedNCurveMethods
49
+ include ProjectedLineStringMethods
50
+
51
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Line).include_in_class(self, true)
52
+ end
53
+
54
+ class ProjectedPolygonImpl # :nodoc:
55
+ include Feature::Polygon
56
+ include ImplHelper::BasicGeometryMethods
57
+ include ImplHelper::BasicPolygonMethods
58
+ include ProjectedGeometryMethods
59
+ include ProjectedNSurfaceMethods
60
+ include ProjectedPolygonMethods
61
+
62
+ Feature::MixinCollection::GLOBAL.for_type(Feature::Polygon).include_in_class(self, true)
63
+ end
64
+
65
+ class ProjectedGeometryCollectionImpl # :nodoc:
66
+ include Feature::GeometryCollection
67
+ include ImplHelper::BasicGeometryMethods
68
+ include ImplHelper::BasicGeometryCollectionMethods
69
+ include ProjectedGeometryMethods
70
+
71
+ Feature::MixinCollection::GLOBAL.for_type(Feature::GeometryCollection).include_in_class(self, true)
72
+ end
73
+
74
+ class ProjectedMultiPointImpl # :nodoc:
75
+ include Feature::MultiPoint
76
+ include ImplHelper::BasicGeometryMethods
77
+ include ImplHelper::BasicGeometryCollectionMethods
78
+ include ImplHelper::BasicMultiPointMethods
79
+ include ProjectedGeometryMethods
80
+
81
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPoint).include_in_class(self, true)
82
+ end
83
+
84
+ class ProjectedMultiLineStringImpl # :nodoc:
85
+ include Feature::MultiLineString
86
+ include ImplHelper::BasicGeometryMethods
87
+ include ImplHelper::BasicGeometryCollectionMethods
88
+ include ImplHelper::BasicMultiLineStringMethods
89
+ include ProjectedGeometryMethods
90
+ include ProjectedNCurveMethods
91
+
92
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiLineString).include_in_class(self, true)
93
+ end
94
+
95
+ class ProjectedMultiPolygonImpl # :nodoc:
96
+ include Feature::MultiPolygon
97
+ include ImplHelper::BasicGeometryMethods
98
+ include ImplHelper::BasicGeometryCollectionMethods
99
+ include ImplHelper::BasicMultiPolygonMethods
100
+ include ProjectedGeometryMethods
101
+ include ProjectedNSurfaceMethods
102
+ include ProjectedMultiPolygonMethods
103
+
104
+ Feature::MixinCollection::GLOBAL.for_type(Feature::MultiPolygon).include_in_class(self, true)
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,212 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Projected geographic common method definitions
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ module ProjectedGeometryMethods # :nodoc:
10
+ def srid
11
+ factory.srid
12
+ end
13
+
14
+ def projection
15
+ @projection = factory.project(self) unless defined?(@projection)
16
+ @projection
17
+ end
18
+
19
+ def envelope
20
+ factory.unproject(projection.envelope)
21
+ end
22
+
23
+ def is_empty?
24
+ projection.is_empty?
25
+ end
26
+
27
+ def is_simple?
28
+ projection.is_simple?
29
+ end
30
+
31
+ def boundary
32
+ boundary_ = projection.boundary
33
+ boundary_ ? factory.unproject(boundary_) : nil
34
+ end
35
+
36
+ def equals?(rhs_)
37
+ projection.equals?(Feature.cast(rhs_, factory).projection)
38
+ end
39
+
40
+ def disjoint?(rhs_)
41
+ projection.disjoint?(Feature.cast(rhs_, factory).projection)
42
+ end
43
+
44
+ def intersects?(rhs_)
45
+ projection.intersects?(Feature.cast(rhs_, factory).projection)
46
+ end
47
+
48
+ def touches?(rhs_)
49
+ projection.touches?(Feature.cast(rhs_, factory).projection)
50
+ end
51
+
52
+ def crosses?(rhs_)
53
+ projection.crosses?(Feature.cast(rhs_, factory).projection)
54
+ end
55
+
56
+ def within?(rhs_)
57
+ projection.within?(Feature.cast(rhs_, factory).projection)
58
+ end
59
+
60
+ def contains?(rhs_)
61
+ projection.contains?(Feature.cast(rhs_, factory).projection)
62
+ end
63
+
64
+ def overlaps?(rhs_)
65
+ projection.overlaps?(Feature.cast(rhs_, factory).projection)
66
+ end
67
+
68
+ def relate(rhs_, pattern_)
69
+ projection.relate(Feature.cast(rhs_, factory).projection, pattern_)
70
+ end
71
+
72
+ def distance(rhs_)
73
+ projection.distance(Feature.cast(rhs_, factory).projection)
74
+ end
75
+
76
+ def buffer(distance_)
77
+ factory.unproject(projection.buffer(distance_))
78
+ end
79
+
80
+ def buffer_with_style(distance_, endCapStyle_, joinStyle_, mitreLimit_)
81
+ factory.unproject(projection.buffer_with_style(distance_, endCapStyle_, joinStyle_, mitreLimit_))
82
+ end
83
+
84
+ def simplify(tolerance_)
85
+ factory.unproject(projection.simplify(tolerance_))
86
+ end
87
+
88
+ def simplify_preserve_topology(tolerance_)
89
+ factory.unproject(projection.simplify_preserve_topology(tolerance_))
90
+ end
91
+
92
+ def convex_hull
93
+ factory.unproject(projection.convex_hull)
94
+ end
95
+
96
+ def intersection(rhs_)
97
+ factory.unproject(projection.intersection(Feature.cast(rhs_, factory).projection))
98
+ end
99
+
100
+ def union(rhs_)
101
+ factory.unproject(projection.union(Feature.cast(rhs_, factory).projection))
102
+ end
103
+
104
+ def difference(rhs_)
105
+ factory.unproject(projection.difference(Feature.cast(rhs_, factory).projection))
106
+ end
107
+
108
+ def sym_difference(rhs_)
109
+ factory.unproject(projection.sym_difference(Feature.cast(rhs_, factory).projection))
110
+ end
111
+ end
112
+
113
+ module ProjectedPointMethods # :nodoc:
114
+ def _validate_geometry
115
+ @y = 85.0511287 if @y > 85.0511287
116
+ @y = -85.0511287 if @y < -85.0511287
117
+ super
118
+ end
119
+
120
+ def canonical_x
121
+ x_ = @x % 360.0
122
+ x_ -= 360.0 if x_ > 180.0
123
+ x_
124
+ end
125
+ alias_method :canonical_longitude, :canonical_x
126
+ alias_method :canonical_lon, :canonical_x
127
+
128
+ def canonical_point
129
+ if @x >= -180.0 && @x < 180.0
130
+ self
131
+ else
132
+ PointImpl.new(@factory, canonical_x, @y)
133
+ end
134
+ end
135
+
136
+ def self.included(klass_)
137
+ klass_.module_eval do
138
+ alias_method :longitude, :x
139
+ alias_method :lon, :x
140
+ alias_method :latitude, :y
141
+ alias_method :lat, :y
142
+ end
143
+ end
144
+ end
145
+
146
+ module ProjectedNCurveMethods # :nodoc:
147
+ def length
148
+ projection.length
149
+ end
150
+ end
151
+
152
+ module ProjectedLineStringMethods # :nodoc:
153
+ def _validate_geometry
154
+ size_ = @points.size
155
+ if size_ > 1
156
+ last_ = @points[0]
157
+ (1...size_).each do |i_|
158
+ p_ = @points[i_]
159
+ last_x_ = last_.x
160
+ p_x_ = p_.x
161
+ changed_ = true
162
+ if p_x_ < last_x_ - 180.0
163
+ p_x_ += 360.0 while p_x_ < last_x_ - 180.0
164
+ elsif p_x_ > last_x_ + 180.0
165
+ p_x_ -= 360.0 while p_x_ > last_x_ + 180.0
166
+ else
167
+ changed_ = false
168
+ end
169
+ if changed_
170
+ p_ = factory.point(p_x_, p_.y)
171
+ @points[i_] = p_
172
+ end
173
+ last_ = p_
174
+ end
175
+ end
176
+ super
177
+ end
178
+ end
179
+
180
+ module ProjectedNSurfaceMethods # :nodoc:
181
+ def area
182
+ projection.area
183
+ end
184
+
185
+ def centroid
186
+ factory.unproject(projection.centroid)
187
+ end
188
+
189
+ def point_on_surface
190
+ factory.unproject(projection.point_on_surface)
191
+ end
192
+ end
193
+
194
+ module ProjectedPolygonMethods # :nodoc:
195
+ def _validate_geometry
196
+ super
197
+ unless projection
198
+ raise Error::InvalidGeometry, "Polygon failed assertions"
199
+ end
200
+ end
201
+ end
202
+
203
+ module ProjectedMultiPolygonMethods # :nodoc:
204
+ def _validate_geometry
205
+ super
206
+ unless projection
207
+ raise Error::InvalidGeometry, "MultiPolygon failed assertions"
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,383 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # A projected window in a geography implementation
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geographic
9
+ # This object represents an axis-aligned rectangle in a map projection
10
+ # coordinate system. It is commonly used to specify the viewport for a
11
+ # map visualization, an envelope in a projected coordinate system, or
12
+ # a spatial constraint. It must be attached to a Geographic::Factory
13
+ # that has a projection.
14
+
15
+ class ProjectedWindow
16
+ # Create a new ProjectedWindow given the Geographic::Factory, and the
17
+ # x and y extents of the rectangle.
18
+ #
19
+ # The window will be intelligently clamped to the limits imposed by
20
+ # the factory. For example, the simple mercator factory limits
21
+ # latitude to approximately +/-85 degrees.
22
+ #
23
+ # Generally, you will not need to call this low-level constructor
24
+ # directly. Instead, use one of the provided class methods.
25
+
26
+ def initialize(factory_, x_min_, y_min_, x_max_, y_max_, opts_ = {})
27
+ @factory = factory_
28
+ limits_ = opts_[:is_limits] ? nil : factory_.projection_limits_window
29
+ wraps_ = factory_.projection_wraps?
30
+ y_max_, y_min_ = y_min_, y_max_ if y_max_ < y_min_
31
+ x_max_, x_min_ = x_min_, x_max_ if x_max_ < x_min_ && !wraps_
32
+ if limits_
33
+ y_max_ = limits_.y_max if y_max_ > limits_.y_max
34
+ y_min_ = limits_.y_min if y_min_ < limits_.y_min
35
+ if wraps_
36
+ width_ = limits_.x_span
37
+ if x_max_ - x_min_ > width_
38
+ center_ = (x_max_ + x_min_) * 0.5
39
+ x_min_ = center_ - width_ * 0.499999999
40
+ x_max_ = center_ + width_ * 0.499999999
41
+ end
42
+ x_max_ = x_max_ % width_
43
+ x_max_ -= width_ if x_max_ >= limits_.x_max
44
+ x_min_ = x_min_ % width_
45
+ x_min_ -= width_ if x_min_ >= limits_.x_max
46
+ else
47
+ x_max_ = limits_.x_max if x_max_ > limits_.x_max
48
+ x_min_ = limits_.x_min if x_min_ < limits_.x_min
49
+ end
50
+ end
51
+ @x_min = x_min_
52
+ @y_min = y_min_
53
+ @x_max = x_max_
54
+ @y_max = y_max_
55
+ end
56
+
57
+ def to_s # :nodoc:
58
+ "#<#{self.class}:0x#{object_id.to_s(16)} s=#{@y_min} w=#{@x_min} n=#{@y_max} e=#{@x_max}>"
59
+ end
60
+
61
+ def inspect # :nodoc:
62
+ to_s
63
+ end
64
+
65
+ def eql?(obj_) # :nodoc:
66
+ return false unless obj_.is_a?(ProjectedWindow)
67
+ @factory == obj_.factory && @x_min == obj_.x_min && @x_max == obj_.x_max &&
68
+ @y_min = obj_.y_min && @y_max = obj_.y_max
69
+ end
70
+ alias_method :==, :eql?
71
+
72
+ def hash # :nodoc:
73
+ @factory.hash + @x_min.hash + @x_max.hash + @y_min.hash + @y_max.hash
74
+ end
75
+
76
+ # Returns the Geographic::Factory associated with this window.
77
+ # Note that this factory is the overall geography factory, not the
78
+ # projected factory (which can be obtained by calling
79
+ # Geographic::Factory#projection_factory on this factory).
80
+
81
+ attr_reader :factory
82
+
83
+ # Returns the lower limit in the x (easting) direction.
84
+
85
+ attr_reader :x_min
86
+
87
+ # Returns the upper limit in the x (easting) direction.
88
+
89
+ attr_reader :x_max
90
+
91
+ # Returns the lower limit in the y (northing) direction.
92
+
93
+ attr_reader :y_min
94
+
95
+ # Returns the upper limit in the y (northing) direction.
96
+
97
+ attr_reader :y_max
98
+
99
+ # Returns true if the projection wraps along the x axis, and this
100
+ # rectangle crosses that seam.
101
+
102
+ def crosses_seam?
103
+ @x_max < @x_min
104
+ end
105
+
106
+ # Returns true if the rectangle has zero area.
107
+
108
+ def degenerate?
109
+ @x_min == @x_max || @y_min == @y_max
110
+ end
111
+
112
+ # Returns the width of the rectangle.
113
+
114
+ def x_span
115
+ span_ = @x_max - @x_min
116
+ span_ += @factory.projection_limits_window.x_span if span_ < 0
117
+ span_
118
+ end
119
+ alias_method :width, :x_span
120
+
121
+ # Returns the height of the rectangle.
122
+
123
+ def y_span
124
+ @y_max - @y_min
125
+ end
126
+ alias_method :height, :y_span
127
+
128
+ # Returns a two-element array containing the x and y coordinates
129
+ # of the center of the rectangle.
130
+
131
+ def center_xy
132
+ y_ = (@y_min + @y_max) * 0.5
133
+ if @x_min > @x_max
134
+ x_ = @x_min + x_span * 0.5
135
+ limits_ = @factory.projection_limits_window
136
+ x_ -= limits_.x_span if x_ >= limits_.x_max
137
+ else
138
+ x_ = (@x_min + @x_max) * 0.5
139
+ end
140
+ [x_, y_]
141
+ end
142
+
143
+ # Returns the southwest corner of the rectangle in _unprojected_
144
+ # (lat/lng) space, as a Feature::Point object.
145
+
146
+ def sw_point
147
+ @sw ||= @factory.unproject(@factory.projection_factory.point(@x_min, @y_min))
148
+ end
149
+
150
+ # Returns the southeast corner of the rectangle in _unprojected_
151
+ # (lat/lng) space, as a Feature::Point object.
152
+
153
+ def se_point
154
+ @se ||= @factory.unproject(@factory.projection_factory.point(@x_max, @y_min))
155
+ end
156
+
157
+ # Returns the northwest corner of the rectangle in _unprojected_
158
+ # (lat/lng) space, as a Feature::Point object.
159
+
160
+ def nw_point
161
+ @nw ||= @factory.unproject(@factory.projection_factory.point(@x_min, @y_max))
162
+ end
163
+
164
+ # Returns the northeast corner of the rectangle in _unprojected_
165
+ # (lat/lng) space, as a Feature::Point object.
166
+
167
+ def ne_point
168
+ @ne ||= @factory.unproject(@factory.projection_factory.point(@x_max, @y_max))
169
+ end
170
+
171
+ # Returns the center of the rectangle in _unprojected_
172
+ # (lat/lng) space, as a Feature::Point object.
173
+
174
+ def center_point
175
+ @center ||= @factory.unproject(@factory.projection_factory.point(*center_xy))
176
+ end
177
+
178
+ # Returns a random point inside the rectangle in _unprojected_
179
+ # (lat/lng) space, as a Feature::Point object.
180
+
181
+ def random_point
182
+ y_ = @y_min + y_span * rand
183
+ x_ = @x_min + x_span * rand
184
+ limits_ = @factory.projection_limits_window
185
+ x_ -= limits_.x_span if x_ >= limits_.x_max
186
+ @factory.unproject(@factory.projection_factory.point(x_, y_))
187
+ end
188
+
189
+ # Returns true if the rectangle contains the given point, which
190
+ # must be a Feature::Point in _unprojected_ (lat/lng) space.
191
+
192
+ def contains_point?(point_)
193
+ projection_ = @factory.project(point_)
194
+ y_ = projection_.y
195
+ if y_ <= @y_max && y_ >= @y_min
196
+ x_ = projection_.x
197
+ limits_ = @factory.projection_limits_window
198
+ width_ = limits_.x_span
199
+ x_ = x_ % width_
200
+ x_ -= width_ if x_ >= limits_.x_max
201
+ if @x_max < @x_min
202
+ x_ <= @x_max || x_ >= @x_min
203
+ else
204
+ x_ <= @x_max && x_ >= @x_min
205
+ end
206
+ else
207
+ false
208
+ end
209
+ end
210
+
211
+ # Returns true if the given window is completely contained within
212
+ # this window.
213
+
214
+ def contains_window?(window_)
215
+ return nil if window_.factory != @factory
216
+ if window_.y_max <= @y_max && window_.y_min >= @y_min
217
+ if (@x_max < @x_min) == window_.crosses_seam?
218
+ window_.x_max <= @x_max && window_.x_min >= @x_min
219
+ else
220
+ @x_max < @x_min && (window_.x_max <= @x_max || window_.x_min >= @x_min)
221
+ end
222
+ else
223
+ false
224
+ end
225
+ end
226
+
227
+ # Returns a new window resulting from scaling this window by the
228
+ # given factors, which must be floating-point values.
229
+ # If y_factor is not explicitly given, it defaults to the same as
230
+ # the x_factor.
231
+
232
+ def scaled_by(x_factor_, y_factor_ = nil)
233
+ y_factor_ ||= x_factor_
234
+ if x_factor_ != 1.0 || y_factor_ != 1.0
235
+ x_, y_ = *center_xy
236
+ xr_ = x_span * 0.5 * x_factor_
237
+ yr_ = y_span * 0.5 * y_factor_
238
+ ProjectedWindow.new(@factory, x_ - xr_, y_ - yr_, x_ + xr_, y_ + yr_)
239
+ else
240
+ self
241
+ end
242
+ end
243
+ alias_method :*, :scaled_by
244
+
245
+ # Returns a new window resulting from clamping this window to the
246
+ # given minimum and maximum widths and heights, in the projected
247
+ # coordinate system. The center of the resulting window is the
248
+ # same as the center of this window. Any of the arguments may be
249
+ # given as nil, indicating no constraint.
250
+
251
+ def clamped_by(min_width_, min_height_, max_width_, max_height_)
252
+ xr_ = x_span
253
+ yr_ = y_span
254
+ changed_ = false
255
+ if min_width_ && xr_ < min_width_
256
+ changed_ = true
257
+ xr_ = min_width_
258
+ end
259
+ if max_width_ && xr_ > max_width_
260
+ changed_ = true
261
+ xr_ = max_width_
262
+ end
263
+ if min_height_ && yr_ < min_height_
264
+ changed_ = true
265
+ yr_ = min_height_
266
+ end
267
+ if max_height_ && yr_ > max_height_
268
+ changed_ = true
269
+ yr_ = max_height_
270
+ end
271
+ if changed_
272
+ x_, y_ = *center_xy
273
+ xr_ *= 0.5
274
+ yr_ *= 0.5
275
+ ProjectedWindow.new(@factory, x_ - xr_, y_ - yr_, x_ + xr_, y_ + yr_)
276
+ else
277
+ self
278
+ end
279
+ end
280
+
281
+ # Returns a new window resulting from adding the given margin to
282
+ # this window. If y_margin is not given, it defaults to the same
283
+ # value as x_margin. Note that the margins may be negative to
284
+ # indicate shrinking of the window.
285
+
286
+ def with_margin(x_margin_, y_margin_ = nil)
287
+ y_margin_ ||= x_margin_
288
+ if x_margin_ != 0.0 || y_margin_ != 0.0
289
+ ProjectedWindow.new(@factory, @x_min - x_margin_, @y_min - y_margin_,
290
+ @x_max + x_margin_, @y_max + y_margin_)
291
+ else
292
+ self
293
+ end
294
+ end
295
+
296
+ class << self
297
+ # Creates a new window whose coordinates are the given points,
298
+ # which must be Feature::Point objects in unprojected (lat/lng)
299
+ # space.
300
+
301
+ def for_corners(sw_, ne_)
302
+ factory_ = sw_.factory
303
+ psw_ = factory_.project(sw_)
304
+ pne_ = factory_.project(ne_)
305
+ ProjectedWindow.new(factory_, psw_.x, psw_.y, pne_.x, pne_.y)
306
+ end
307
+
308
+ # Creates a new window that surrounds the given point with the
309
+ # given margin. The point must be a Feature::Point object in
310
+ # unprojected (lat/lng) space, while the margins are numbers in
311
+ # projected space. The y_margin may be given as nil, in which
312
+ # case it is set to the same as the x_margin.
313
+
314
+ def surrounding_point(point_, x_margin_ = nil, y_margin_ = nil)
315
+ x_margin_ ||= 0.0
316
+ y_margin_ ||= x_margin_
317
+ factory_ = point_.factory
318
+ projection_ = factory_.project(point_)
319
+ ProjectedWindow.new(factory_, projection_.x - x_margin_, projection_.y - y_margin_,
320
+ projection_.x + x_margin_, projection_.y + y_margin_)
321
+ end
322
+
323
+ # Creates a new window that contains all of the given points.
324
+ # which must be Feature::Point objects in unprojected (lat/lng)
325
+ # space.
326
+
327
+ def bounding_points(points_)
328
+ factory_ = nil
329
+ limits_ = nil
330
+ width_ = nil
331
+ x_max_ = nil
332
+ x_min_ = nil
333
+ y_max_ = nil
334
+ y_min_ = nil
335
+ x_array_ = nil
336
+ points_.each do |p_|
337
+ unless factory_
338
+ factory_ = p_.factory
339
+ limits_ = factory_.projection_limits_window
340
+ width_ = limits_.x_span
341
+ x_array_ = [] if factory_.projection_wraps?
342
+ end
343
+ proj_ = factory_.project(p_)
344
+ x_ = proj_.x
345
+ if x_array_
346
+ x_ = x_ % width_
347
+ x_ -= width_ if x_ >= limits_.x_max
348
+ x_array_ << x_
349
+ else
350
+ x_max_ = x_ if !x_max_ || x_max_ < x_
351
+ x_min_ = x_ if !x_min_ || x_min_ > x_
352
+ end
353
+ y_ = proj_.y
354
+ y_max_ = y_ if !y_max_ || y_max_ < y_
355
+ y_min_ = y_ if !y_min_ || y_min_ > y_
356
+ end
357
+ return nil unless factory_
358
+ if x_array_
359
+ x_array_.sort!
360
+ largest_span_ = nil
361
+ last_ = x_array_.last
362
+ x_array_.each do |x_|
363
+ if largest_span_
364
+ span_ = x_ - last_
365
+ if span_ > largest_span_
366
+ largest_span_ = span_
367
+ x_min_ = x_
368
+ x_max_ = last_
369
+ end
370
+ else
371
+ largest_span_ = x_ - last_ + width_
372
+ x_min_ = x_
373
+ x_max_ = last_
374
+ end
375
+ last_ = x_
376
+ end
377
+ end
378
+ ProjectedWindow.new(factory_, x_min_, y_min_, x_max_, y_max_)
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end