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.
- data/History.rdoc +199 -0
- data/README.rdoc +172 -0
- data/Spatial_Programming_With_RGeo.rdoc +440 -0
- data/Version +1 -0
- data/ext/geos_c_impl/extconf.rb +84 -0
- data/ext/geos_c_impl/factory.c +468 -0
- data/ext/geos_c_impl/factory.h +224 -0
- data/ext/geos_c_impl/geometry.c +705 -0
- data/ext/geos_c_impl/geometry.h +55 -0
- data/ext/geos_c_impl/geometry_collection.c +482 -0
- data/ext/geos_c_impl/geometry_collection.h +69 -0
- data/ext/geos_c_impl/line_string.c +509 -0
- data/ext/geos_c_impl/line_string.h +64 -0
- data/ext/geos_c_impl/main.c +70 -0
- data/ext/geos_c_impl/point.c +193 -0
- data/ext/geos_c_impl/point.h +62 -0
- data/ext/geos_c_impl/polygon.c +265 -0
- data/ext/geos_c_impl/polygon.h +66 -0
- data/ext/geos_c_impl/preface.h +50 -0
- data/ext/proj4_c_impl/extconf.rb +88 -0
- data/ext/proj4_c_impl/main.c +271 -0
- data/lib/rgeo.rb +124 -0
- data/lib/rgeo/cartesian.rb +60 -0
- data/lib/rgeo/cartesian/analysis.rb +118 -0
- data/lib/rgeo/cartesian/bounding_box.rb +337 -0
- data/lib/rgeo/cartesian/calculations.rb +161 -0
- data/lib/rgeo/cartesian/factory.rb +209 -0
- data/lib/rgeo/cartesian/feature_classes.rb +173 -0
- data/lib/rgeo/cartesian/feature_methods.rb +106 -0
- data/lib/rgeo/cartesian/interface.rb +150 -0
- data/lib/rgeo/coord_sys.rb +79 -0
- data/lib/rgeo/coord_sys/cs/entities.rb +1524 -0
- data/lib/rgeo/coord_sys/cs/factories.rb +208 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +308 -0
- data/lib/rgeo/coord_sys/proj4.rb +312 -0
- data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +194 -0
- data/lib/rgeo/coord_sys/srs_database/interface.rb +165 -0
- data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +188 -0
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +108 -0
- data/lib/rgeo/coord_sys/srs_database/url_reader.rb +108 -0
- data/lib/rgeo/error.rb +63 -0
- data/lib/rgeo/feature.rb +88 -0
- data/lib/rgeo/feature/curve.rb +156 -0
- data/lib/rgeo/feature/factory.rb +332 -0
- data/lib/rgeo/feature/factory_generator.rb +138 -0
- data/lib/rgeo/feature/geometry.rb +614 -0
- data/lib/rgeo/feature/geometry_collection.rb +129 -0
- data/lib/rgeo/feature/line.rb +66 -0
- data/lib/rgeo/feature/line_string.rb +102 -0
- data/lib/rgeo/feature/linear_ring.rb +66 -0
- data/lib/rgeo/feature/multi_curve.rb +113 -0
- data/lib/rgeo/feature/multi_line_string.rb +66 -0
- data/lib/rgeo/feature/multi_point.rb +73 -0
- data/lib/rgeo/feature/multi_polygon.rb +97 -0
- data/lib/rgeo/feature/multi_surface.rb +116 -0
- data/lib/rgeo/feature/point.rb +120 -0
- data/lib/rgeo/feature/polygon.rb +141 -0
- data/lib/rgeo/feature/surface.rb +122 -0
- data/lib/rgeo/feature/types.rb +305 -0
- data/lib/rgeo/geographic.rb +75 -0
- data/lib/rgeo/geographic/factory.rb +287 -0
- data/lib/rgeo/geographic/interface.rb +410 -0
- data/lib/rgeo/geographic/proj4_projector.rb +98 -0
- data/lib/rgeo/geographic/projected_feature_classes.rb +213 -0
- data/lib/rgeo/geographic/projected_feature_methods.rb +228 -0
- data/lib/rgeo/geographic/projected_window.rb +467 -0
- data/lib/rgeo/geographic/simple_mercator_projector.rb +157 -0
- data/lib/rgeo/geographic/spherical_feature_classes.rb +212 -0
- data/lib/rgeo/geographic/spherical_feature_methods.rb +97 -0
- data/lib/rgeo/geographic/spherical_math.rb +206 -0
- data/lib/rgeo/geos.rb +72 -0
- data/lib/rgeo/geos/factory.rb +301 -0
- data/lib/rgeo/geos/impl_additions.rb +76 -0
- data/lib/rgeo/geos/interface.rb +139 -0
- data/lib/rgeo/geos/zm_factory.rb +275 -0
- data/lib/rgeo/geos/zm_impl.rb +432 -0
- data/lib/rgeo/impl_helper.rb +53 -0
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +235 -0
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +85 -0
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +197 -0
- data/lib/rgeo/impl_helper/basic_point_methods.rb +138 -0
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +121 -0
- data/lib/rgeo/impl_helper/math.rb +50 -0
- data/lib/rgeo/version.rb +52 -0
- data/lib/rgeo/wkrep.rb +72 -0
- data/lib/rgeo/wkrep/wkb_generator.rb +267 -0
- data/lib/rgeo/wkrep/wkb_parser.rb +315 -0
- data/lib/rgeo/wkrep/wkt_generator.rb +275 -0
- data/lib/rgeo/wkrep/wkt_parser.rb +496 -0
- data/test/common/geometry_collection_tests.rb +238 -0
- data/test/common/line_string_tests.rb +324 -0
- data/test/common/multi_line_string_tests.rb +209 -0
- data/test/common/multi_point_tests.rb +201 -0
- data/test/common/multi_polygon_tests.rb +208 -0
- data/test/common/point_tests.rb +331 -0
- data/test/common/polygon_tests.rb +232 -0
- data/test/coord_sys/tc_active_record_table.rb +102 -0
- data/test/coord_sys/tc_ogc_cs.rb +356 -0
- data/test/coord_sys/tc_proj4.rb +138 -0
- data/test/coord_sys/tc_proj4_srs_data.rb +76 -0
- data/test/coord_sys/tc_sr_org.rb +70 -0
- data/test/coord_sys/tc_url_reader.rb +82 -0
- data/test/geos/tc_factory.rb +91 -0
- data/test/geos/tc_geometry_collection.rb +62 -0
- data/test/geos/tc_line_string.rb +62 -0
- data/test/geos/tc_misc.rb +72 -0
- data/test/geos/tc_multi_line_string.rb +62 -0
- data/test/geos/tc_multi_point.rb +62 -0
- data/test/geos/tc_multi_polygon.rb +63 -0
- data/test/geos/tc_point.rb +86 -0
- data/test/geos/tc_polygon.rb +86 -0
- data/test/geos/tc_zmfactory.rb +85 -0
- data/test/projected_geographic/tc_geometry_collection.rb +62 -0
- data/test/projected_geographic/tc_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_line_string.rb +62 -0
- data/test/projected_geographic/tc_multi_point.rb +62 -0
- data/test/projected_geographic/tc_multi_polygon.rb +63 -0
- data/test/projected_geographic/tc_point.rb +93 -0
- data/test/projected_geographic/tc_polygon.rb +62 -0
- data/test/simple_cartesian/tc_calculations.rb +145 -0
- data/test/simple_cartesian/tc_geometry_collection.rb +69 -0
- data/test/simple_cartesian/tc_line_string.rb +70 -0
- data/test/simple_cartesian/tc_multi_line_string.rb +67 -0
- data/test/simple_cartesian/tc_multi_point.rb +67 -0
- data/test/simple_cartesian/tc_multi_polygon.rb +70 -0
- data/test/simple_cartesian/tc_point.rb +91 -0
- data/test/simple_cartesian/tc_polygon.rb +67 -0
- data/test/simple_mercator/tc_geometry_collection.rb +62 -0
- data/test/simple_mercator/tc_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_line_string.rb +62 -0
- data/test/simple_mercator/tc_multi_point.rb +62 -0
- data/test/simple_mercator/tc_multi_polygon.rb +63 -0
- data/test/simple_mercator/tc_point.rb +93 -0
- data/test/simple_mercator/tc_polygon.rb +62 -0
- data/test/simple_mercator/tc_window.rb +219 -0
- data/test/spherical_geographic/tc_calculations.rb +203 -0
- data/test/spherical_geographic/tc_geometry_collection.rb +70 -0
- data/test/spherical_geographic/tc_line_string.rb +70 -0
- data/test/spherical_geographic/tc_multi_line_string.rb +67 -0
- data/test/spherical_geographic/tc_multi_point.rb +67 -0
- data/test/spherical_geographic/tc_multi_polygon.rb +70 -0
- data/test/spherical_geographic/tc_point.rb +100 -0
- data/test/spherical_geographic/tc_polygon.rb +67 -0
- data/test/tc_cartesian_analysis.rb +107 -0
- data/test/tc_oneoff.rb +63 -0
- data/test/wkrep/tc_wkb_generator.rb +249 -0
- data/test/wkrep/tc_wkb_parser.rb +353 -0
- data/test/wkrep/tc_wkt_generator.rb +362 -0
- data/test/wkrep/tc_wkt_parser.rb +480 -0
- 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
|