rgeo-dschee 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +29 -0
  3. data/ext/geos_c_impl/coordinates.c +65 -0
  4. data/ext/geos_c_impl/coordinates.h +2 -0
  5. data/ext/geos_c_impl/extconf.rb +43 -0
  6. data/ext/geos_c_impl/factory.c +995 -0
  7. data/ext/geos_c_impl/factory.h +238 -0
  8. data/ext/geos_c_impl/geometry.c +1093 -0
  9. data/ext/geos_c_impl/geometry.h +23 -0
  10. data/ext/geos_c_impl/geometry_collection.c +757 -0
  11. data/ext/geos_c_impl/geometry_collection.h +46 -0
  12. data/ext/geos_c_impl/line_string.c +675 -0
  13. data/ext/geos_c_impl/line_string.h +32 -0
  14. data/ext/geos_c_impl/main.c +40 -0
  15. data/ext/geos_c_impl/point.c +236 -0
  16. data/ext/geos_c_impl/point.h +30 -0
  17. data/ext/geos_c_impl/polygon.c +359 -0
  18. data/ext/geos_c_impl/polygon.h +43 -0
  19. data/ext/geos_c_impl/preface.h +38 -0
  20. data/ext/proj4_c_impl/extconf.rb +62 -0
  21. data/ext/proj4_c_impl/main.c +315 -0
  22. data/lib/rgeo.rb +89 -0
  23. data/lib/rgeo/cartesian.rb +25 -0
  24. data/lib/rgeo/cartesian/analysis.rb +77 -0
  25. data/lib/rgeo/cartesian/bounding_box.rb +398 -0
  26. data/lib/rgeo/cartesian/calculations.rb +113 -0
  27. data/lib/rgeo/cartesian/factory.rb +347 -0
  28. data/lib/rgeo/cartesian/feature_classes.rb +100 -0
  29. data/lib/rgeo/cartesian/feature_methods.rb +88 -0
  30. data/lib/rgeo/cartesian/interface.rb +135 -0
  31. data/lib/rgeo/coord_sys.rb +43 -0
  32. data/lib/rgeo/coord_sys/cs/entities.rb +1315 -0
  33. data/lib/rgeo/coord_sys/cs/factories.rb +148 -0
  34. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +272 -0
  35. data/lib/rgeo/coord_sys/proj4.rb +293 -0
  36. data/lib/rgeo/coord_sys/srs_database/interface.rb +115 -0
  37. data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +140 -0
  38. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +62 -0
  39. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +63 -0
  40. data/lib/rgeo/error.rb +27 -0
  41. data/lib/rgeo/feature.rb +54 -0
  42. data/lib/rgeo/feature/curve.rb +111 -0
  43. data/lib/rgeo/feature/factory.rb +278 -0
  44. data/lib/rgeo/feature/factory_generator.rb +96 -0
  45. data/lib/rgeo/feature/geometry.rb +624 -0
  46. data/lib/rgeo/feature/geometry_collection.rb +95 -0
  47. data/lib/rgeo/feature/line.rb +26 -0
  48. data/lib/rgeo/feature/line_string.rb +60 -0
  49. data/lib/rgeo/feature/linear_ring.rb +26 -0
  50. data/lib/rgeo/feature/mixins.rb +143 -0
  51. data/lib/rgeo/feature/multi_curve.rb +71 -0
  52. data/lib/rgeo/feature/multi_line_string.rb +26 -0
  53. data/lib/rgeo/feature/multi_point.rb +33 -0
  54. data/lib/rgeo/feature/multi_polygon.rb +57 -0
  55. data/lib/rgeo/feature/multi_surface.rb +73 -0
  56. data/lib/rgeo/feature/point.rb +84 -0
  57. data/lib/rgeo/feature/polygon.rb +97 -0
  58. data/lib/rgeo/feature/surface.rb +79 -0
  59. data/lib/rgeo/feature/types.rb +284 -0
  60. data/lib/rgeo/geographic.rb +40 -0
  61. data/lib/rgeo/geographic/factory.rb +450 -0
  62. data/lib/rgeo/geographic/interface.rb +489 -0
  63. data/lib/rgeo/geographic/proj4_projector.rb +58 -0
  64. data/lib/rgeo/geographic/projected_feature_classes.rb +107 -0
  65. data/lib/rgeo/geographic/projected_feature_methods.rb +212 -0
  66. data/lib/rgeo/geographic/projected_window.rb +383 -0
  67. data/lib/rgeo/geographic/simple_mercator_projector.rb +110 -0
  68. data/lib/rgeo/geographic/spherical_feature_classes.rb +100 -0
  69. data/lib/rgeo/geographic/spherical_feature_methods.rb +134 -0
  70. data/lib/rgeo/geographic/spherical_math.rb +188 -0
  71. data/lib/rgeo/geos.rb +89 -0
  72. data/lib/rgeo/geos/capi_factory.rb +470 -0
  73. data/lib/rgeo/geos/capi_feature_classes.rb +129 -0
  74. data/lib/rgeo/geos/ffi_factory.rb +592 -0
  75. data/lib/rgeo/geos/ffi_feature_classes.rb +83 -0
  76. data/lib/rgeo/geos/ffi_feature_methods.rb +574 -0
  77. data/lib/rgeo/geos/interface.rb +202 -0
  78. data/lib/rgeo/geos/utils.rb +74 -0
  79. data/lib/rgeo/geos/zm_factory.rb +405 -0
  80. data/lib/rgeo/geos/zm_feature_classes.rb +80 -0
  81. data/lib/rgeo/geos/zm_feature_methods.rb +344 -0
  82. data/lib/rgeo/impl_helper.rb +19 -0
  83. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +185 -0
  84. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +61 -0
  85. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +146 -0
  86. data/lib/rgeo/impl_helper/basic_point_methods.rb +104 -0
  87. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +87 -0
  88. data/lib/rgeo/impl_helper/math.rb +14 -0
  89. data/lib/rgeo/impl_helper/utils.rb +29 -0
  90. data/lib/rgeo/version.rb +3 -0
  91. data/lib/rgeo/wkrep.rb +37 -0
  92. data/lib/rgeo/wkrep/wkb_generator.rb +201 -0
  93. data/lib/rgeo/wkrep/wkb_parser.rb +251 -0
  94. data/lib/rgeo/wkrep/wkt_generator.rb +207 -0
  95. data/lib/rgeo/wkrep/wkt_parser.rb +415 -0
  96. data/lib/rgeo/yaml.rb +23 -0
  97. data/test/cartesian_analysis_test.rb +65 -0
  98. data/test/cartesian_bbox_test.rb +123 -0
  99. data/test/common/factory_tests.rb +78 -0
  100. data/test/common/geometry_collection_tests.rb +237 -0
  101. data/test/common/line_string_tests.rb +330 -0
  102. data/test/common/multi_line_string_tests.rb +182 -0
  103. data/test/common/multi_point_tests.rb +200 -0
  104. data/test/common/multi_polygon_tests.rb +191 -0
  105. data/test/common/point_tests.rb +370 -0
  106. data/test/common/polygon_tests.rb +261 -0
  107. data/test/coord_sys/ogc_cs_test.rb +342 -0
  108. data/test/coord_sys/proj4_srs_data_test.rb +41 -0
  109. data/test/coord_sys/proj4_test.rb +150 -0
  110. data/test/coord_sys/sr_org_test.rb +32 -0
  111. data/test/coord_sys/url_reader_test.rb +42 -0
  112. data/test/geos_capi/factory_test.rb +31 -0
  113. data/test/geos_capi/geometry_collection_test.rb +24 -0
  114. data/test/geos_capi/line_string_test.rb +24 -0
  115. data/test/geos_capi/misc_test.rb +116 -0
  116. data/test/geos_capi/multi_line_string_test.rb +24 -0
  117. data/test/geos_capi/multi_point_test.rb +24 -0
  118. data/test/geos_capi/multi_polygon_test.rb +39 -0
  119. data/test/geos_capi/parsing_unparsing_test.rb +40 -0
  120. data/test/geos_capi/point_test.rb +72 -0
  121. data/test/geos_capi/polygon_test.rb +154 -0
  122. data/test/geos_capi/zmfactory_test.rb +57 -0
  123. data/test/geos_ffi/factory_test.rb +31 -0
  124. data/test/geos_ffi/geometry_collection_test.rb +24 -0
  125. data/test/geos_ffi/line_string_test.rb +24 -0
  126. data/test/geos_ffi/misc_test.rb +63 -0
  127. data/test/geos_ffi/multi_line_string_test.rb +24 -0
  128. data/test/geos_ffi/multi_point_test.rb +24 -0
  129. data/test/geos_ffi/multi_polygon_test.rb +33 -0
  130. data/test/geos_ffi/parsing_unparsing_test.rb +41 -0
  131. data/test/geos_ffi/point_test.rb +77 -0
  132. data/test/geos_ffi/polygon_test.rb +46 -0
  133. data/test/geos_ffi/zmfactory_test.rb +58 -0
  134. data/test/mixins_test.rb +141 -0
  135. data/test/oneoff_test.rb +26 -0
  136. data/test/projected_geographic/factory_test.rb +25 -0
  137. data/test/projected_geographic/geometry_collection_test.rb +24 -0
  138. data/test/projected_geographic/line_string_test.rb +24 -0
  139. data/test/projected_geographic/multi_line_string_test.rb +26 -0
  140. data/test/projected_geographic/multi_point_test.rb +30 -0
  141. data/test/projected_geographic/multi_polygon_test.rb +25 -0
  142. data/test/projected_geographic/point_test.rb +51 -0
  143. data/test/projected_geographic/polygon_test.rb +24 -0
  144. data/test/simple_cartesian/calculations_test.rb +99 -0
  145. data/test/simple_cartesian/factory_test.rb +27 -0
  146. data/test/simple_cartesian/geometry_collection_test.rb +30 -0
  147. data/test/simple_cartesian/line_string_test.rb +31 -0
  148. data/test/simple_cartesian/multi_line_string_test.rb +28 -0
  149. data/test/simple_cartesian/multi_point_test.rb +31 -0
  150. data/test/simple_cartesian/multi_polygon_test.rb +31 -0
  151. data/test/simple_cartesian/point_test.rb +50 -0
  152. data/test/simple_cartesian/polygon_test.rb +28 -0
  153. data/test/simple_mercator/factory_test.rb +25 -0
  154. data/test/simple_mercator/geometry_collection_test.rb +24 -0
  155. data/test/simple_mercator/line_string_test.rb +24 -0
  156. data/test/simple_mercator/multi_line_string_test.rb +26 -0
  157. data/test/simple_mercator/multi_point_test.rb +29 -0
  158. data/test/simple_mercator/multi_polygon_test.rb +25 -0
  159. data/test/simple_mercator/point_test.rb +55 -0
  160. data/test/simple_mercator/polygon_test.rb +24 -0
  161. data/test/simple_mercator/window_test.rb +173 -0
  162. data/test/spherical_geographic/calculations_test.rb +167 -0
  163. data/test/spherical_geographic/factory_test.rb +27 -0
  164. data/test/spherical_geographic/geometry_collection_test.rb +31 -0
  165. data/test/spherical_geographic/line_string_test.rb +31 -0
  166. data/test/spherical_geographic/multi_line_string_test.rb +29 -0
  167. data/test/spherical_geographic/multi_point_test.rb +31 -0
  168. data/test/spherical_geographic/multi_polygon_test.rb +31 -0
  169. data/test/spherical_geographic/point_test.rb +78 -0
  170. data/test/spherical_geographic/polygon_test.rb +28 -0
  171. data/test/types_test.rb +42 -0
  172. data/test/wkrep/wkb_generator_test.rb +185 -0
  173. data/test/wkrep/wkb_parser_test.rb +293 -0
  174. data/test/wkrep/wkt_generator_test.rb +294 -0
  175. data/test/wkrep/wkt_parser_test.rb +412 -0
  176. metadata +386 -0
@@ -0,0 +1,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