schleyfox-rgeo 0.2.5

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 (150) hide show
  1. data/History.rdoc +199 -0
  2. data/README.rdoc +172 -0
  3. data/Spatial_Programming_With_RGeo.rdoc +440 -0
  4. data/Version +1 -0
  5. data/ext/geos_c_impl/extconf.rb +84 -0
  6. data/ext/geos_c_impl/factory.c +468 -0
  7. data/ext/geos_c_impl/factory.h +224 -0
  8. data/ext/geos_c_impl/geometry.c +705 -0
  9. data/ext/geos_c_impl/geometry.h +55 -0
  10. data/ext/geos_c_impl/geometry_collection.c +482 -0
  11. data/ext/geos_c_impl/geometry_collection.h +69 -0
  12. data/ext/geos_c_impl/line_string.c +509 -0
  13. data/ext/geos_c_impl/line_string.h +64 -0
  14. data/ext/geos_c_impl/main.c +70 -0
  15. data/ext/geos_c_impl/point.c +193 -0
  16. data/ext/geos_c_impl/point.h +62 -0
  17. data/ext/geos_c_impl/polygon.c +265 -0
  18. data/ext/geos_c_impl/polygon.h +66 -0
  19. data/ext/geos_c_impl/preface.h +50 -0
  20. data/ext/proj4_c_impl/extconf.rb +88 -0
  21. data/ext/proj4_c_impl/main.c +271 -0
  22. data/lib/rgeo.rb +124 -0
  23. data/lib/rgeo/cartesian.rb +60 -0
  24. data/lib/rgeo/cartesian/analysis.rb +118 -0
  25. data/lib/rgeo/cartesian/bounding_box.rb +337 -0
  26. data/lib/rgeo/cartesian/calculations.rb +161 -0
  27. data/lib/rgeo/cartesian/factory.rb +209 -0
  28. data/lib/rgeo/cartesian/feature_classes.rb +173 -0
  29. data/lib/rgeo/cartesian/feature_methods.rb +106 -0
  30. data/lib/rgeo/cartesian/interface.rb +150 -0
  31. data/lib/rgeo/coord_sys.rb +79 -0
  32. data/lib/rgeo/coord_sys/cs/entities.rb +1524 -0
  33. data/lib/rgeo/coord_sys/cs/factories.rb +208 -0
  34. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +308 -0
  35. data/lib/rgeo/coord_sys/proj4.rb +312 -0
  36. data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +194 -0
  37. data/lib/rgeo/coord_sys/srs_database/interface.rb +165 -0
  38. data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +188 -0
  39. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +108 -0
  40. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +108 -0
  41. data/lib/rgeo/error.rb +63 -0
  42. data/lib/rgeo/feature.rb +88 -0
  43. data/lib/rgeo/feature/curve.rb +156 -0
  44. data/lib/rgeo/feature/factory.rb +332 -0
  45. data/lib/rgeo/feature/factory_generator.rb +138 -0
  46. data/lib/rgeo/feature/geometry.rb +614 -0
  47. data/lib/rgeo/feature/geometry_collection.rb +129 -0
  48. data/lib/rgeo/feature/line.rb +66 -0
  49. data/lib/rgeo/feature/line_string.rb +102 -0
  50. data/lib/rgeo/feature/linear_ring.rb +66 -0
  51. data/lib/rgeo/feature/multi_curve.rb +113 -0
  52. data/lib/rgeo/feature/multi_line_string.rb +66 -0
  53. data/lib/rgeo/feature/multi_point.rb +73 -0
  54. data/lib/rgeo/feature/multi_polygon.rb +97 -0
  55. data/lib/rgeo/feature/multi_surface.rb +116 -0
  56. data/lib/rgeo/feature/point.rb +120 -0
  57. data/lib/rgeo/feature/polygon.rb +141 -0
  58. data/lib/rgeo/feature/surface.rb +122 -0
  59. data/lib/rgeo/feature/types.rb +305 -0
  60. data/lib/rgeo/geographic.rb +75 -0
  61. data/lib/rgeo/geographic/factory.rb +287 -0
  62. data/lib/rgeo/geographic/interface.rb +410 -0
  63. data/lib/rgeo/geographic/proj4_projector.rb +98 -0
  64. data/lib/rgeo/geographic/projected_feature_classes.rb +213 -0
  65. data/lib/rgeo/geographic/projected_feature_methods.rb +228 -0
  66. data/lib/rgeo/geographic/projected_window.rb +467 -0
  67. data/lib/rgeo/geographic/simple_mercator_projector.rb +157 -0
  68. data/lib/rgeo/geographic/spherical_feature_classes.rb +212 -0
  69. data/lib/rgeo/geographic/spherical_feature_methods.rb +97 -0
  70. data/lib/rgeo/geographic/spherical_math.rb +206 -0
  71. data/lib/rgeo/geos.rb +72 -0
  72. data/lib/rgeo/geos/factory.rb +301 -0
  73. data/lib/rgeo/geos/impl_additions.rb +76 -0
  74. data/lib/rgeo/geos/interface.rb +139 -0
  75. data/lib/rgeo/geos/zm_factory.rb +275 -0
  76. data/lib/rgeo/geos/zm_impl.rb +432 -0
  77. data/lib/rgeo/impl_helper.rb +53 -0
  78. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +235 -0
  79. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +85 -0
  80. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +197 -0
  81. data/lib/rgeo/impl_helper/basic_point_methods.rb +138 -0
  82. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +121 -0
  83. data/lib/rgeo/impl_helper/math.rb +50 -0
  84. data/lib/rgeo/version.rb +52 -0
  85. data/lib/rgeo/wkrep.rb +72 -0
  86. data/lib/rgeo/wkrep/wkb_generator.rb +267 -0
  87. data/lib/rgeo/wkrep/wkb_parser.rb +315 -0
  88. data/lib/rgeo/wkrep/wkt_generator.rb +275 -0
  89. data/lib/rgeo/wkrep/wkt_parser.rb +496 -0
  90. data/test/common/geometry_collection_tests.rb +238 -0
  91. data/test/common/line_string_tests.rb +324 -0
  92. data/test/common/multi_line_string_tests.rb +209 -0
  93. data/test/common/multi_point_tests.rb +201 -0
  94. data/test/common/multi_polygon_tests.rb +208 -0
  95. data/test/common/point_tests.rb +331 -0
  96. data/test/common/polygon_tests.rb +232 -0
  97. data/test/coord_sys/tc_active_record_table.rb +102 -0
  98. data/test/coord_sys/tc_ogc_cs.rb +356 -0
  99. data/test/coord_sys/tc_proj4.rb +138 -0
  100. data/test/coord_sys/tc_proj4_srs_data.rb +76 -0
  101. data/test/coord_sys/tc_sr_org.rb +70 -0
  102. data/test/coord_sys/tc_url_reader.rb +82 -0
  103. data/test/geos/tc_factory.rb +91 -0
  104. data/test/geos/tc_geometry_collection.rb +62 -0
  105. data/test/geos/tc_line_string.rb +62 -0
  106. data/test/geos/tc_misc.rb +72 -0
  107. data/test/geos/tc_multi_line_string.rb +62 -0
  108. data/test/geos/tc_multi_point.rb +62 -0
  109. data/test/geos/tc_multi_polygon.rb +63 -0
  110. data/test/geos/tc_point.rb +86 -0
  111. data/test/geos/tc_polygon.rb +86 -0
  112. data/test/geos/tc_zmfactory.rb +85 -0
  113. data/test/projected_geographic/tc_geometry_collection.rb +62 -0
  114. data/test/projected_geographic/tc_line_string.rb +62 -0
  115. data/test/projected_geographic/tc_multi_line_string.rb +62 -0
  116. data/test/projected_geographic/tc_multi_point.rb +62 -0
  117. data/test/projected_geographic/tc_multi_polygon.rb +63 -0
  118. data/test/projected_geographic/tc_point.rb +93 -0
  119. data/test/projected_geographic/tc_polygon.rb +62 -0
  120. data/test/simple_cartesian/tc_calculations.rb +145 -0
  121. data/test/simple_cartesian/tc_geometry_collection.rb +69 -0
  122. data/test/simple_cartesian/tc_line_string.rb +70 -0
  123. data/test/simple_cartesian/tc_multi_line_string.rb +67 -0
  124. data/test/simple_cartesian/tc_multi_point.rb +67 -0
  125. data/test/simple_cartesian/tc_multi_polygon.rb +70 -0
  126. data/test/simple_cartesian/tc_point.rb +91 -0
  127. data/test/simple_cartesian/tc_polygon.rb +67 -0
  128. data/test/simple_mercator/tc_geometry_collection.rb +62 -0
  129. data/test/simple_mercator/tc_line_string.rb +62 -0
  130. data/test/simple_mercator/tc_multi_line_string.rb +62 -0
  131. data/test/simple_mercator/tc_multi_point.rb +62 -0
  132. data/test/simple_mercator/tc_multi_polygon.rb +63 -0
  133. data/test/simple_mercator/tc_point.rb +93 -0
  134. data/test/simple_mercator/tc_polygon.rb +62 -0
  135. data/test/simple_mercator/tc_window.rb +219 -0
  136. data/test/spherical_geographic/tc_calculations.rb +203 -0
  137. data/test/spherical_geographic/tc_geometry_collection.rb +70 -0
  138. data/test/spherical_geographic/tc_line_string.rb +70 -0
  139. data/test/spherical_geographic/tc_multi_line_string.rb +67 -0
  140. data/test/spherical_geographic/tc_multi_point.rb +67 -0
  141. data/test/spherical_geographic/tc_multi_polygon.rb +70 -0
  142. data/test/spherical_geographic/tc_point.rb +100 -0
  143. data/test/spherical_geographic/tc_polygon.rb +67 -0
  144. data/test/tc_cartesian_analysis.rb +107 -0
  145. data/test/tc_oneoff.rb +63 -0
  146. data/test/wkrep/tc_wkb_generator.rb +249 -0
  147. data/test/wkrep/tc_wkb_parser.rb +353 -0
  148. data/test/wkrep/tc_wkt_generator.rb +362 -0
  149. data/test/wkrep/tc_wkt_parser.rb +480 -0
  150. metadata +267 -0
@@ -0,0 +1,467 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # A projected window in a geography implementation
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module RGeo
38
+
39
+ module Geographic
40
+
41
+
42
+ # This object represents an axis-aligned rectangle in a map projection
43
+ # coordinate system. It is commonly used to specify the viewport for a
44
+ # map visualization, an envelope in a projected coordinate system, or
45
+ # a spatial constraint. It must be attached to a Geographic::Factory
46
+ # that has a projection.
47
+
48
+ class ProjectedWindow
49
+
50
+
51
+ # Create a new ProjectedWindow given the Geographic::Factory, and the
52
+ # x and y extents of the rectangle.
53
+ #
54
+ # The window will be intelligently clamped to the limits imposed by
55
+ # the factory. For example, the simple mercator factory limits
56
+ # latitude to approximately +/-85 degrees.
57
+ #
58
+ # Generally, you will not need to call this low-level constructor
59
+ # directly. Instead, use one of the provided class methods.
60
+
61
+ def initialize(factory_, x_min_, y_min_, x_max_, y_max_, opts_={})
62
+ @factory = factory_
63
+ limits_ = opts_[:is_limits] ? nil : factory_.projection_limits_window
64
+ wraps_ = factory_.projection_wraps?
65
+ y_max_, y_min_ = y_min_, y_max_ if y_max_ < y_min_
66
+ x_max_, x_min_ = x_min_, x_max_ if x_max_ < x_min_ && !wraps_
67
+ if limits_
68
+ y_max_ = limits_.y_max if y_max_ > limits_.y_max
69
+ y_min_ = limits_.y_min if y_min_ < limits_.y_min
70
+ if wraps_
71
+ width_ = limits_.x_span
72
+ if x_max_ - x_min_ > width_
73
+ center_ = (x_max_ + x_min_) * 0.5
74
+ x_min_ = center_ - width_ * 0.499999999
75
+ x_max_ = center_ + width_ * 0.499999999
76
+ end
77
+ x_max_ = x_max_ % width_
78
+ x_max_ -= width_ if x_max_ >= limits_.x_max
79
+ x_min_ = x_min_ % width_
80
+ x_min_ -= width_ if x_min_ >= limits_.x_max
81
+ else
82
+ x_max_ = limits_.x_max if x_max_ > limits_.x_max
83
+ x_min_ = limits_.x_min if x_min_ < limits_.x_min
84
+ end
85
+ end
86
+ @x_min = x_min_
87
+ @y_min = y_min_
88
+ @x_max = x_max_
89
+ @y_max = y_max_
90
+ end
91
+
92
+
93
+ def to_s # :nodoc:
94
+ "#<#{self.class}:0x#{object_id.to_s(16)} s=#{@y_min} w=#{@x_min} n=#{@y_max} e=#{@x_max}>"
95
+ end
96
+
97
+ def inspect # :nodoc:
98
+ to_s
99
+ end
100
+
101
+
102
+ def eql?(obj_) # :nodoc:
103
+ return false unless obj_.kind_of?(ProjectedWindow)
104
+ @factory == obj_.factory && @x_min == obj_.x_min && @x_max == obj_.x_max && @y_min = obj_.y_min && @y_max = obj_.y_max
105
+ end
106
+ alias_method :==, :eql?
107
+
108
+ def hash # :nodoc:
109
+ @factory.hash + @x_min.hash + @x_max.hash + @y_min.hash + @y_max.hash
110
+ end
111
+
112
+
113
+ # Returns the Geographic::Factory associated with this window.
114
+ # Note that this factory is the overall geography factory, not the
115
+ # projected factory (which can be obtained by calling
116
+ # Geographic::Factory#projection_factory on this factory).
117
+
118
+ def factory
119
+ @factory
120
+ end
121
+
122
+
123
+ # Returns the lower limit in the x (easting) direction.
124
+
125
+ def x_min
126
+ @x_min
127
+ end
128
+
129
+
130
+ # Returns the upper limit in the x (easting) direction.
131
+
132
+ def x_max
133
+ @x_max
134
+ end
135
+
136
+
137
+ # Returns the lower limit in the y (northing) direction.
138
+
139
+ def y_min
140
+ @y_min
141
+ end
142
+
143
+
144
+ # Returns the upper limit in the y (northing) direction.
145
+
146
+ def y_max
147
+ @y_max
148
+ end
149
+
150
+
151
+ # Returns true if the projection wraps along the x axis, and this
152
+ # rectangle crosses that seam.
153
+
154
+ def crosses_seam?
155
+ @x_max < @x_min
156
+ end
157
+
158
+
159
+ # Returns true if the rectangle has zero area.
160
+
161
+ def degenerate?
162
+ @x_min == @x_max || @y_min == @y_max
163
+ end
164
+
165
+
166
+ # Returns the width of the rectangle.
167
+
168
+ def x_span
169
+ span_ = @x_max - @x_min
170
+ if span_ < 0
171
+ span_ += @factory.projection_limits_window.x_span
172
+ end
173
+ span_
174
+ end
175
+ alias_method :width, :x_span
176
+
177
+
178
+ # Returns the height of the rectangle.
179
+
180
+ def y_span
181
+ @y_max - @y_min
182
+ end
183
+ alias_method :height, :x_span
184
+
185
+
186
+ # Returns a two-element array containing the x and y coordinates
187
+ # of the center of the rectangle.
188
+
189
+ def center_xy
190
+ y_ = (@y_min + @y_max) * 0.5
191
+ if @x_min > @x_max
192
+ x_ = @x_min + x_span * 0.5
193
+ limits_ = @factory.projection_limits_window
194
+ x_ -= limits_.x_span if x_ >= limits_.x_max
195
+ else
196
+ x_ = (@x_min + @x_max) * 0.5
197
+ end
198
+ [x_, y_]
199
+ end
200
+
201
+
202
+ # Returns the southwest corner of the rectangle in _unprojected_
203
+ # (lat/lng) space, as a Feature::Point object.
204
+
205
+ def sw_point
206
+ @sw ||= @factory.unproject(@factory.projection_factory.point(@x_min, @y_min))
207
+ end
208
+
209
+
210
+ # Returns the southeast corner of the rectangle in _unprojected_
211
+ # (lat/lng) space, as a Feature::Point object.
212
+
213
+ def se_point
214
+ @se ||= @factory.unproject(@factory.projection_factory.point(@x_max, @y_min))
215
+ end
216
+
217
+
218
+ # Returns the northwest corner of the rectangle in _unprojected_
219
+ # (lat/lng) space, as a Feature::Point object.
220
+
221
+ def nw_point
222
+ @nw ||= @factory.unproject(@factory.projection_factory.point(@x_min, @y_max))
223
+ end
224
+
225
+
226
+ # Returns the northeast corner of the rectangle in _unprojected_
227
+ # (lat/lng) space, as a Feature::Point object.
228
+
229
+ def ne_point
230
+ @ne ||= @factory.unproject(@factory.projection_factory.point(@x_max, @y_max))
231
+ end
232
+
233
+
234
+ # Returns the center of the rectangle in _unprojected_
235
+ # (lat/lng) space, as a Feature::Point object.
236
+
237
+ def center_point
238
+ @center ||= @factory.unproject(@factory.projection_factory.point(*center_xy))
239
+ end
240
+
241
+
242
+ # Returns a random point the rectangle in _unprojected_
243
+ # (lat/lng) space, as a Feature::Point object.
244
+
245
+ def random_point
246
+ y_ = @y_min + (@y_max - @y_min) * rand
247
+ if @x_min > @x_max
248
+ x_ = @x_min + x_span * rand
249
+ limits_ = @factory.projection_limits_window
250
+ x_ -= limits_.x_span if x_ >= limits_.x_max
251
+ else
252
+ x_ = (@x_min + @x_max) * rand
253
+ end
254
+ @factory.unproject(@factory.projection_factory.point(x_, y_))
255
+ end
256
+
257
+
258
+ # Returns true if the rectangle contains the given point, which
259
+ # must be a Feature::Point in _unprojected_ (lat/lng) space.
260
+
261
+ def contains_point?(point_)
262
+ projection_ = @factory.project(point_)
263
+ y_ = projection_.y
264
+ if y_ <= @y_max && y_ >= @y_min
265
+ x_ = projection_.x
266
+ limits_ = @factory.projection_limits_window
267
+ width_ = limits_.x_span
268
+ x_ = x_ % width_
269
+ x_ -= width_ if x_ >= limits_.x_max
270
+ if @x_max < @x_min
271
+ x_ <= @x_max || x_ >= @x_min
272
+ else
273
+ x_ <= @x_max && x_ >= @x_min
274
+ end
275
+ else
276
+ false
277
+ end
278
+ end
279
+
280
+
281
+ # Returns true if the given window is completely contained within
282
+ # this window.
283
+
284
+ def contains_window?(window_)
285
+ return nil if window_.factory != @factory
286
+ if window_.y_max <= @y_max && window_.y_min >= @y_min
287
+ if (@x_max < @x_min) == window_.crosses_seam?
288
+ window_.x_max <= @x_max && window_.x_min >= @x_min
289
+ else
290
+ @x_max < @x_min && (window_.x_max <= @x_max || window_.x_min >= @x_min)
291
+ end
292
+ else
293
+ false
294
+ end
295
+ end
296
+
297
+
298
+ # Returns a new window resulting from scaling this window by the
299
+ # given factors, which must be floating-point values.
300
+ # If y_factor is not explicitly given, it defaults to the same as
301
+ # the x_factor.
302
+
303
+ def scaled_by(x_factor_, y_factor_=nil)
304
+ y_factor_ ||= x_factor_
305
+ if x_factor_ != 1.0 || y_factor_ != 1.0
306
+ x_, y_ = *center_xy
307
+ xr_ = x_span * 0.5 * x_factor_
308
+ yr_ = y_span * 0.5 * y_factor_
309
+ ProjectedWindow.new(@factory, x_ - xr_, y_ - yr_, x_ + xr_, y_ + yr_)
310
+ else
311
+ self
312
+ end
313
+ end
314
+ alias_method :*, :scaled_by
315
+
316
+
317
+ # Returns a new window resulting from clamping this window to the
318
+ # given minimum and maximum widths and heights, in the projected
319
+ # coordinate system. The center of the resulting window is the
320
+ # same as the center of this window. Any of the arguments may be
321
+ # given as nil, indicating no constraint.
322
+
323
+ def clamped_by(min_width_, min_height_, max_width_, max_height_)
324
+ xr_ = x_span
325
+ yr_ = y_span
326
+ changed_ = false
327
+ if min_width_ && xr_ < min_width_
328
+ changed_ = true
329
+ xr_ = min_width_
330
+ end
331
+ if max_width_ && xr_ > max_width_
332
+ changed_ = true
333
+ xr_ = max_width_
334
+ end
335
+ if min_height_ && yr_ < min_height_
336
+ changed_ = true
337
+ yr_ = min_height_
338
+ end
339
+ if max_height_ && yr_ > max_height_
340
+ changed_ = true
341
+ yr_ = max_height_
342
+ end
343
+ if changed_
344
+ x_, y_ = *center_xy
345
+ xr_ *= 0.5
346
+ yr_ *= 0.5
347
+ ProjectedWindow.new(@factory, x_ - xr_, y_ - yr_, x_ + xr_, y_ + yr_)
348
+ else
349
+ self
350
+ end
351
+ end
352
+
353
+
354
+ # Returns a new window resulting from adding the given margin to
355
+ # this window. If y_margin is not given, it defaults to the same
356
+ # value as x_margin. Note that the margins may be negative to
357
+ # indicate shrinking of the window.
358
+
359
+ def with_margin(x_margin_, y_margin_=nil)
360
+ y_margin_ ||= x_margin_
361
+ if x_margin_ != 0.0 || y_margin_ != 0.0
362
+ ProjectedWindow.new(@factory, @x_min - x_margin_, @y_min - y_margin_, @x_max + x_margin_, @y_max + y_margin_)
363
+ else
364
+ self
365
+ end
366
+ end
367
+
368
+
369
+ class << self
370
+
371
+
372
+ # Creates a new window whose coordinates are the given points,
373
+ # which must be Feature::Point objects in unprojected (lat/lng)
374
+ # space.
375
+
376
+ def for_corners(sw_, ne_)
377
+ factory_ = sw_.factory
378
+ psw_ = factory_.project(sw_)
379
+ pne_ = factory_.project(ne_)
380
+ ProjectedWindow.new(factory_, psw_.x, psw_.y, pne_.x, pne_.y)
381
+ end
382
+
383
+
384
+ # Creates a new window that surrounds the given point with the
385
+ # given margin. The point must be a Feature::Point object in
386
+ # unprojected (lat/lng) space, while the margins are numbers in
387
+ # projected space. The y_margin may be given as nil, in which
388
+ # case it is set to the same as the x_margin.
389
+
390
+ def surrounding_point(point_, x_margin_=nil, y_margin_=nil)
391
+ x_margin_ ||= 0.0
392
+ y_margin_ ||= x_margin_
393
+ factory_ = point_.factory
394
+ projection_ = factory_.project(point_)
395
+ ProjectedWindow.new(factory_, projection_.x - x_margin_, projection_.y - y_margin_,
396
+ projection_.x + x_margin_, projection_.y + y_margin_)
397
+ end
398
+
399
+
400
+ # Creates a new window that contains all of the given points.
401
+ # which must be Feature::Point objects in unprojected (lat/lng)
402
+ # space.
403
+
404
+ def bounding_points(points_)
405
+ factory_ = nil
406
+ limits_ = nil
407
+ width_ = nil
408
+ x_max_ = nil
409
+ x_min_ = nil
410
+ y_max_ = nil
411
+ y_min_ = nil
412
+ x_array_ = nil
413
+ points_.each do |p_|
414
+ unless factory_
415
+ factory_ = p_.factory
416
+ limits_ = factory_.projection_limits_window
417
+ width_ = limits_.x_span
418
+ x_array_ = [] if factory_.projection_wraps?
419
+ end
420
+ proj_ = factory_.project(p_)
421
+ x_ = proj_.x
422
+ if x_array_
423
+ x_ = x_ % width_
424
+ x_ -= width_ if x_ >= limits_.x_max
425
+ x_array_ << x_
426
+ else
427
+ x_max_ = x_ if !x_max_ || x_max_ < x_
428
+ x_min_ = x_ if !x_min_ || x_min_ > x_
429
+ end
430
+ y_ = proj_.y
431
+ y_max_ = y_ if !y_max_ || y_max_ < y_
432
+ y_min_ = y_ if !y_min_ || y_min_ > y_
433
+ end
434
+ return nil unless factory_
435
+ if x_array_
436
+ x_array_.sort!
437
+ largest_span_ = nil
438
+ last_ = x_array_.last
439
+ x_array_.each do |x_|
440
+ if largest_span_
441
+ span_ = x_ - last_
442
+ if span_ > largest_span_
443
+ largest_span_ = span_
444
+ x_min_ = x_
445
+ x_max_ = last_
446
+ end
447
+ else
448
+ largest_span_ = x_ - last_ + width_
449
+ x_min_ = x_
450
+ x_max_ = last_
451
+ end
452
+ last_ = x_
453
+ end
454
+ end
455
+ ProjectedWindow.new(factory_, x_min_, y_min_, x_max_, y_max_)
456
+ end
457
+
458
+
459
+ end
460
+
461
+
462
+ end
463
+
464
+
465
+ end
466
+
467
+ end