rgeo 0.1.10 → 0.1.11

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 (43) hide show
  1. data/History.rdoc +13 -0
  2. data/README.rdoc +6 -0
  3. data/Version +1 -1
  4. data/ext/geos_c_impl/factory.c +2 -2
  5. data/lib/rgeo/features/factory.rb +2 -2
  6. data/lib/rgeo/features/geometry.rb +26 -4
  7. data/lib/rgeo/features/geometry_collection.rb +12 -2
  8. data/lib/rgeo/geography/common/geometry_collection_methods.rb +12 -1
  9. data/lib/rgeo/geography/common/helper.rb +4 -4
  10. data/lib/rgeo/geography/common/line_string_methods.rb +1 -1
  11. data/lib/rgeo/geography/common/point_methods.rb +1 -1
  12. data/lib/rgeo/geography/common/polygon_methods.rb +1 -1
  13. data/lib/rgeo/geography/factories.rb +19 -6
  14. data/lib/rgeo/geography/factory.rb +31 -10
  15. data/lib/rgeo/geography/simple_mercator/feature_classes.rb +26 -26
  16. data/lib/rgeo/geography/simple_mercator/feature_methods.rb +14 -14
  17. data/lib/rgeo/geography/simple_mercator/projector.rb +1 -1
  18. data/lib/rgeo/geography/simple_spherical/calculations.rb +61 -0
  19. data/lib/rgeo/geography/simple_spherical/point_impl.rb +5 -0
  20. data/lib/rgeo/geos/factory.rb +12 -11
  21. data/tests/common/geometry_collection_tests.rb +220 -0
  22. data/tests/common/line_string_tests.rb +300 -0
  23. data/tests/common/multi_line_string_tests.rb +206 -0
  24. data/tests/common/multi_point_tests.rb +198 -0
  25. data/tests/common/multi_polygon_tests.rb +206 -0
  26. data/tests/common/point_tests.rb +281 -0
  27. data/tests/common/polygon_tests.rb +232 -0
  28. data/tests/geos/tc_geometry_collection.rb +5 -169
  29. data/tests/geos/tc_line_string.rb +4 -252
  30. data/tests/geos/tc_multi_line_string.rb +5 -154
  31. data/tests/geos/tc_multi_point.rb +5 -145
  32. data/tests/geos/tc_multi_polygon.rb +4 -151
  33. data/tests/geos/tc_point.rb +11 -213
  34. data/tests/geos/tc_polygon.rb +4 -182
  35. data/tests/simple_mercator/tc_geometry_collection.rb +62 -0
  36. data/tests/simple_mercator/tc_line_string.rb +62 -0
  37. data/tests/simple_mercator/tc_multi_line_string.rb +62 -0
  38. data/tests/simple_mercator/tc_multi_point.rb +62 -0
  39. data/tests/simple_mercator/tc_multi_polygon.rb +63 -0
  40. data/tests/simple_mercator/tc_point.rb +7 -220
  41. data/tests/simple_mercator/tc_polygon.rb +62 -0
  42. data/tests/simple_spherical/tc_point.rb +165 -0
  43. metadata +48 -9
data/History.rdoc CHANGED
@@ -1,3 +1,16 @@
1
+ === 0.1.11 / 2010-10-21
2
+
3
+ Further development and fixing in the geographic coordinate systems.
4
+
5
+ Changes since 0.1.10:
6
+
7
+ * API CHANGE: Factory#convert renamed to Factory#coerce.
8
+ * Some implementations that inherit from RGeo::Features::Geometry (e.g. the Geography implementations) raised Unimplemented from operator implementations because they had aliased the wrong methods. Fixed.
9
+ * Geos coercer didn't properly coerce "contained" elements in a compound geometry. Fixed.
10
+ * The SimpleMercator and SimpleSpherical factories failed to properly check and coerce inputs into the typed collection methods. Fixed.
11
+ * The options for the SimpleMercator factory were not documented and didn't work. Fixed.
12
+ * A bunch of additional test cases and minor fixes for SimpleMercator and SimpleSpherical.
13
+
1
14
  === 0.1.10 / 2010-10-19
2
15
 
3
16
  Initial public release. This release is considered pre-alpha quality and is being released for experimentation and feedback. We are using it in production in a limited capacity at GeoPage, but we do not yet recommend general production deployment because there are a number of known bugs and incomplete areas, and many features and APIs are still in flux.
data/README.rdoc CHANGED
@@ -8,6 +8,12 @@ storage systems such as PostGIS. It also provides a suite of useful tools
8
8
  for writing location-based applications using Ruby-based frameworks such
9
9
  as Ruby On Rails.
10
10
 
11
+ IMPORTANT: RGeo is currently under development, and we consider it to be
12
+ in a "pre-alpha" state. A number of features (such as Rails integration)
13
+ are not yet complete, and there are numerous known bugs and holes in the
14
+ test suite. We also expect the APIs to be in flux for a short while
15
+ longer. Therefore, we do not yet recommend the use of RGeo in production.
16
+
11
17
  === Summary
12
18
 
13
19
  RGeo is a core component for writing location-based applications in the
data/Version CHANGED
@@ -1 +1 @@
1
- 0.1.10
1
+ 0.1.11
@@ -332,7 +332,7 @@ VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VAL
332
332
 
333
333
  const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj)
334
334
  {
335
- VALUE object = rb_funcall(factory, rb_intern("convert"), 1, obj);
335
+ VALUE object = rb_funcall(factory, rb_intern("coerce"), 1, obj);
336
336
  const GEOSGeometry* geom = NULL;
337
337
  if (!NIL_P(object)) {
338
338
  geom = RGEO_GET_GEOS_GEOMETRY(object);
@@ -346,7 +346,7 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(RGeo_Globals* globals, VALU
346
346
  if (klasses) {
347
347
  *klasses = Qnil;
348
348
  }
349
- VALUE object = rb_funcall(globals->default_factory, rb_intern("convert"), 2, obj, Qtrue);
349
+ VALUE object = rb_funcall(globals->default_factory, rb_intern("coerce"), 2, obj, Qtrue);
350
350
  GEOSGeometry* geom = NULL;
351
351
  if (!NIL_P(object)) {
352
352
  geom = RGEO_GEOMETRY_DATA_PTR(object)->geom;
@@ -173,12 +173,12 @@ module RGeo
173
173
  end
174
174
 
175
175
 
176
- # Convert an existing feature to a feature of the type created by
176
+ # Coerce an existing feature to a feature of the type created by
177
177
  # this implementation.
178
178
  # If force_new is true, a new object is returned even if the original
179
179
  # is already of this implementation.
180
180
 
181
- def convert(original_, force_new_=false)
181
+ def coerce(original_, force_new_=false)
182
182
  nil
183
183
  end
184
184
 
@@ -546,10 +546,32 @@ module RGeo
546
546
  end
547
547
 
548
548
 
549
- alias_method :==, :equals?
550
- alias_method :-, :difference
551
- alias_method :+, :union
552
- alias_method :*, :intersection
549
+ # Alias of the equals? method.
550
+
551
+ def ==(rhs_)
552
+ equals?(rhs_)
553
+ end
554
+
555
+
556
+ # Alias of the difference method.
557
+
558
+ def -(rhs_)
559
+ difference(rhs_)
560
+ end
561
+
562
+
563
+ # Alias of the union method.
564
+
565
+ def +(rhs_)
566
+ union(rhs_)
567
+ end
568
+
569
+
570
+ # Alias of the intersection method.
571
+
572
+ def *(rhs_)
573
+ intersection(rhs_)
574
+ end
553
575
 
554
576
 
555
577
  end
@@ -94,8 +94,18 @@ module RGeo
94
94
  end
95
95
 
96
96
 
97
- alias_method :size, :num_geometries
98
- alias_method :[], :geometry_n
97
+ # Alias of the num_geometries method.
98
+
99
+ def size
100
+ num_geometries
101
+ end
102
+
103
+
104
+ # Alias of the geometry_n method.
105
+
106
+ def [](n_)
107
+ geometry_n(n_)
108
+ end
99
109
 
100
110
 
101
111
  # Iterates over the geometries of this GeometryCollection.
@@ -44,8 +44,19 @@ module RGeo
44
44
  module GeometryCollectionMethods
45
45
 
46
46
 
47
+ def self._check_types(enum_, type_)
48
+ enum_.all? do |elem_|
49
+ case elem_
50
+ when type_ then true
51
+ when Features::GeometryCollection then _check_types(elem_, type_)
52
+ else false
53
+ end
54
+ end
55
+ end
56
+
57
+
47
58
  def _setup(elements_)
48
- @elements = elements_.map{ |elem_| factory.convert(elem_) }
59
+ @elements = elements_.map{ |elem_| factory.coerce(elem_) }
49
60
  _validate_geometry
50
61
  end
51
62
 
@@ -69,26 +69,26 @@ module RGeo
69
69
  def self.parse_wkt(str_, factory_)
70
70
  helper_factory_ = self.factory
71
71
  obj_ = helper_factory_ ? helper_factory_.parse_wkt(str_) : nil
72
- obj_ ? factory_.convert(obj_) : nil
72
+ obj_ ? factory_.coerce(obj_) : nil
73
73
  end
74
74
 
75
75
 
76
76
  def self.parse_wkb(str_, factory_)
77
77
  helper_factory_ = self.factory
78
78
  obj_ = helper_factory_ ? helper_factory_.parse_wkb(str_) : nil
79
- obj_ ? factory_.convert(obj_) : nil
79
+ obj_ ? factory_.coerce(obj_) : nil
80
80
  end
81
81
 
82
82
 
83
83
  def self.unparse_wkt(obj_)
84
84
  helper_factory_ = self.factory
85
- helper_factory_ ? helper_factory_.convert(obj_).as_text : nil
85
+ helper_factory_ ? helper_factory_.coerce(obj_).as_text : nil
86
86
  end
87
87
 
88
88
 
89
89
  def self.unparse_wkb(obj_)
90
90
  helper_factory_ = self.factory
91
- helper_factory_ ? helper_factory_.convert(obj_).as_binary : nil
91
+ helper_factory_ ? helper_factory_.coerce(obj_).as_binary : nil
92
92
  end
93
93
 
94
94
 
@@ -45,7 +45,7 @@ module RGeo
45
45
 
46
46
 
47
47
  def _setup(points_)
48
- @points = points_.map{ |elem_| factory.convert(elem_) }
48
+ @points = points_.map{ |elem_| factory.coerce(elem_) }
49
49
  _validate_geometry
50
50
  end
51
51
 
@@ -113,7 +113,7 @@ module RGeo
113
113
 
114
114
  def equals?(rhs_)
115
115
  return false unless rhs_.factory.is_a?(Factory)
116
- rhs_ = factory.convert(rhs_)
116
+ rhs_ = factory.coerce(rhs_)
117
117
  case rhs_
118
118
  when Features::Point
119
119
  if @y == 90
@@ -46,7 +46,7 @@ module RGeo
46
46
 
47
47
  def _setup(exterior_ring_, interior_rings_)
48
48
  @exterior_ring = exterior_ring_
49
- @interior_rings = (interior_rings_ || []).map{ |elem_| factory.convert(elem_) }
49
+ @interior_rings = (interior_rings_ || []).map{ |elem_| factory.coerce(elem_) }
50
50
  unless Features::LinearRing.check_type(@exterior_ring)
51
51
  raise Errors::InvalidGeometry, 'Exterior ring must be a LinearRing'
52
52
  end
@@ -38,9 +38,6 @@ module RGeo
38
38
 
39
39
  module Geography
40
40
 
41
- @simple_spherical = nil
42
- @simple_mercator = nil
43
-
44
41
  class << self
45
42
 
46
43
 
@@ -75,8 +72,8 @@ module RGeo
75
72
  # than those generated by, e.g., PostGIS (unless you direct PostGIS
76
73
  # to use spherical geodesics).
77
74
 
78
- def simple_spherical(opts_={}) # :nodoc:
79
- @simple_spherical ||= Geography::Factory.new(Geography::SimpleSpherical)
75
+ def simple_spherical(opts_={})
76
+ Geography::Factory.new(Geography::SimpleSpherical)
80
77
  end
81
78
 
82
79
 
@@ -123,9 +120,25 @@ module RGeo
123
120
  # describes the <i>actual</i> behavior of the common map
124
121
  # visualization APIs, so we've decided to fudge on this in the
125
122
  # interest of being true to our expected application use cases.
123
+ #
124
+ # Supported options include:
125
+ #
126
+ # <tt>:lenient_multi_polygon_assertions</tt>::
127
+ # If set to true, assertion checking on MultiPolygon is disabled.
128
+ # This may speed up creation of MultiPolygon objects, at the
129
+ # expense of not doing the proper checking for OGC MultiPolygon
130
+ # compliance. Default is false.
131
+ # <tt>:buffer_resolution</tt>::
132
+ # The resolution of buffers around geometries created by this
133
+ # factory. This controls the number of line segments used to
134
+ # approximate curves. The default is 1, which causes, for
135
+ # example, the buffer around a point to be approximated by a
136
+ # 4-sided polygon. A resolution of 2 would cause that buffer
137
+ # to be approximated by an 8-sided polygon. The exact behavior
138
+ # for different kinds of buffers is not specified.
126
139
 
127
140
  def simple_mercator(opts_={})
128
- @simple_mercator ||= Geography::Factory.new(Geography::SimpleMercator, :buffer_resolution => opts_[:buffer_resolution])
141
+ Geography::Factory.new(Geography::SimpleMercator, :buffer_resolution => opts_[:buffer_resolution], :lenient_multi_polygon_assertions => opts_[:lenient_multi_polygon_assertions])
129
142
  end
130
143
 
131
144
 
@@ -189,6 +189,8 @@ module RGeo
189
189
  # See ::RGeo::Features::Factory#multi_point
190
190
 
191
191
  def multi_point(elems_)
192
+ elems_ = _flatten(elems_, Features::Point)
193
+ return nil unless elems_
192
194
  @namespace.const_get(:MultiPointImpl).new(self, elems_) rescue nil
193
195
  end
194
196
 
@@ -196,6 +198,8 @@ module RGeo
196
198
  # See ::RGeo::Features::Factory#multi_line_string
197
199
 
198
200
  def multi_line_string(elems_)
201
+ elems_ = _flatten(elems_, Features::LineString)
202
+ return nil unless elems_
199
203
  @namespace.const_get(:MultiLineStringImpl).new(self, elems_) rescue nil
200
204
  end
201
205
 
@@ -203,13 +207,15 @@ module RGeo
203
207
  # See ::RGeo::Features::Factory#multi_polygon
204
208
 
205
209
  def multi_polygon(elems_)
210
+ elems_ = _flatten(elems_, Features::Polygon)
211
+ return nil unless elems_
206
212
  @namespace.const_get(:MultiPolygonImpl).new(self, elems_) rescue nil
207
213
  end
208
214
 
209
215
 
210
- # See ::RGeo::Features::Factory#convert
216
+ # See ::RGeo::Features::Factory#coerce
211
217
 
212
- def convert(original_, force_new_=false)
218
+ def coerce(original_, force_new_=false)
213
219
  if self == original_.factory
214
220
  force_new_ ? original_.dup : original_
215
221
  else
@@ -217,21 +223,21 @@ module RGeo
217
223
  when Features::Point
218
224
  @namespace.const_get(:PointImpl).new(self, original_.x, original_.y) rescue nil
219
225
  when Features::Line
220
- @namespace.const_get(:LineImpl).new(self, original_.start_point, original_.end_point) rescue nil
226
+ @namespace.const_get(:LineImpl).new(self, coerce(original_.start_point), coerce(original_.end_point)) rescue nil
221
227
  when Features::LinearRing
222
- @namespace.const_get(:LinearRingImpl).new(self, original_.points) rescue nil
228
+ @namespace.const_get(:LinearRingImpl).new(self, original_.points.map{ |g_| coerce(g_) }) rescue nil
223
229
  when Features::LineString
224
- @namespace.const_get(:LineStringImpl).new(self, original_.points) rescue nil
230
+ @namespace.const_get(:LineStringImpl).new(self, original_.points.map{ |g_| coerce(g_) }) rescue nil
225
231
  when Features::Polygon
226
- @namespace.const_get(:PolygonImpl).new(self, original_.exterior_ring, original_.interior_rings) rescue nil
232
+ @namespace.const_get(:PolygonImpl).new(self, coerce(original_.exterior_ring), original_.interior_rings.map{ |g_| coerce(g_) }) rescue nil
227
233
  when Features::MultiPoint
228
- @namespace.const_get(:MultiPointImpl).new(self, original_.to_a) rescue nil
234
+ @namespace.const_get(:MultiPointImpl).new(self, original_.to_a.map{ |g_| coerce(g_) }) rescue nil
229
235
  when Features::MultiLineString
230
- @namespace.const_get(:MultiLineStringImpl).new(self, original_.to_a) rescue nil
236
+ @namespace.const_get(:MultiLineStringImpl).new(self, original_.to_a.map{ |g_| coerce(g_) }) rescue nil
231
237
  when Features::MultiPolygon
232
- @namespace.const_get(:MultiPolygonImpl).new(self, original_.to_a) rescue nil
238
+ @namespace.const_get(:MultiPolygonImpl).new(self, original_.to_a.map{ |g_| coerce(g_) }) rescue nil
233
239
  when Features::GeometryCollection
234
- @namespace.const_get(:GeometryCollectionImpl).new(self, original_.to_a) rescue nil
240
+ @namespace.const_get(:GeometryCollectionImpl).new(self, original_.to_a.map{ |g_| coerce(g_) }) rescue nil
235
241
  else
236
242
  nil
237
243
  end
@@ -239,6 +245,21 @@ module RGeo
239
245
  end
240
246
 
241
247
 
248
+ def _flatten(elems_, type_, array_=[])
249
+ elems_.each do |elem_|
250
+ case elem_
251
+ when type_
252
+ array_ << elem_
253
+ when Features::GeometryCollection
254
+ return nil unless _flatten(elem_, type_, array_)
255
+ else
256
+ return nil
257
+ end
258
+ end
259
+ array_
260
+ end
261
+
262
+
242
263
  end
243
264
 
244
265
  end
@@ -46,7 +46,7 @@ module RGeo
46
46
 
47
47
  include Features::Point
48
48
  include Common::GeometryMethods
49
- include GeometryMethods
49
+ include SimpleMercator::GeometryMethods
50
50
  include Common::PointMethods
51
51
 
52
52
 
@@ -95,11 +95,11 @@ module RGeo
95
95
 
96
96
  include Features::LineString
97
97
  include Common::GeometryMethods
98
- include GeometryMethods
99
- include NCurveMethods
100
- include CurveMethods
98
+ include SimpleMercator::GeometryMethods
99
+ include SimpleMercator::NCurveMethods
100
+ include SimpleMercator::CurveMethods
101
101
  include Common::LineStringMethods
102
- include LineStringMethods
102
+ include SimpleMercator::LineStringMethods
103
103
 
104
104
 
105
105
  def initialize(factory_, points_)
@@ -121,11 +121,11 @@ module RGeo
121
121
 
122
122
  include Features::Line
123
123
  include Common::GeometryMethods
124
- include GeometryMethods
125
- include NCurveMethods
126
- include CurveMethods
124
+ include SimpleMercator::GeometryMethods
125
+ include SimpleMercator::NCurveMethods
126
+ include SimpleMercator::CurveMethods
127
127
  include Common::LineStringMethods
128
- include LineStringMethods
128
+ include SimpleMercator::LineStringMethods
129
129
  include Common::LinearRingMethods
130
130
 
131
131
 
@@ -148,11 +148,11 @@ module RGeo
148
148
 
149
149
  include Features::Line
150
150
  include Common::GeometryMethods
151
- include GeometryMethods
152
- include NCurveMethods
153
- include CurveMethods
151
+ include SimpleMercator::GeometryMethods
152
+ include SimpleMercator::NCurveMethods
153
+ include SimpleMercator::CurveMethods
154
154
  include Common::LineStringMethods
155
- include LineStringMethods
155
+ include SimpleMercator::LineStringMethods
156
156
  include Common::LineMethods
157
157
 
158
158
 
@@ -175,9 +175,9 @@ module RGeo
175
175
 
176
176
  include Features::Polygon
177
177
  include Common::GeometryMethods
178
- include GeometryMethods
179
- include NSurfaceMethods
180
- include SurfaceMethods
178
+ include SimpleMercator::GeometryMethods
179
+ include SimpleMercator::NSurfaceMethods
180
+ include SimpleMercator::SurfaceMethods
181
181
  include Common::PolygonMethods
182
182
 
183
183
 
@@ -209,9 +209,9 @@ module RGeo
209
209
 
210
210
  include Features::GeometryCollection
211
211
  include Common::GeometryMethods
212
- include GeometryMethods
212
+ include SimpleMercator::GeometryMethods
213
213
  include Common::GeometryCollectionMethods
214
- include GeometryCollectionMethods
214
+ include SimpleMercator::GeometryCollectionMethods
215
215
 
216
216
 
217
217
  def initialize(factory_, elements_)
@@ -233,9 +233,9 @@ module RGeo
233
233
 
234
234
  include Features::GeometryCollection
235
235
  include Common::GeometryMethods
236
- include GeometryMethods
236
+ include SimpleMercator::GeometryMethods
237
237
  include Common::GeometryCollectionMethods
238
- include GeometryCollectionMethods
238
+ include SimpleMercator::GeometryCollectionMethods
239
239
  include Common::MultiPointMethods
240
240
 
241
241
 
@@ -258,10 +258,10 @@ module RGeo
258
258
 
259
259
  include Features::GeometryCollection
260
260
  include Common::GeometryMethods
261
- include GeometryMethods
262
- include NCurveMethods
261
+ include SimpleMercator::GeometryMethods
262
+ include SimpleMercator::NCurveMethods
263
263
  include Common::GeometryCollectionMethods
264
- include GeometryCollectionMethods
264
+ include SimpleMercator::GeometryCollectionMethods
265
265
  include Common::MultiLineStringMethods
266
266
 
267
267
 
@@ -284,10 +284,10 @@ module RGeo
284
284
 
285
285
  include Features::GeometryCollection
286
286
  include Common::GeometryMethods
287
- include GeometryMethods
288
- include NSurfaceMethods
287
+ include SimpleMercator::GeometryMethods
288
+ include SimpleMercator::NSurfaceMethods
289
289
  include Common::GeometryCollectionMethods
290
- include GeometryCollectionMethods
290
+ include SimpleMercator::GeometryCollectionMethods
291
291
  include Common::MultiPolygonMethods
292
292
 
293
293
 
@@ -103,52 +103,52 @@ module RGeo
103
103
 
104
104
 
105
105
  def equals?(rhs_)
106
- projection.equals?(factory.convert(rhs_).projection)
106
+ projection.equals?(factory.coerce(rhs_).projection)
107
107
  end
108
108
 
109
109
 
110
110
  def disjoint?(rhs_)
111
- projection.disjoint?(factory.convert(rhs_).projection)
111
+ projection.disjoint?(factory.coerce(rhs_).projection)
112
112
  end
113
113
 
114
114
 
115
115
  def intersects?(rhs_)
116
- projection.intersects?(factory.convert(rhs_).projection)
116
+ projection.intersects?(factory.coerce(rhs_).projection)
117
117
  end
118
118
 
119
119
 
120
120
  def touches?(rhs_)
121
- projection.touches?(factory.convert(rhs_).projection)
121
+ projection.touches?(factory.coerce(rhs_).projection)
122
122
  end
123
123
 
124
124
 
125
125
  def crosses?(rhs_)
126
- projection.crosses?(factory.convert(rhs_).projection)
126
+ projection.crosses?(factory.coerce(rhs_).projection)
127
127
  end
128
128
 
129
129
 
130
130
  def within?(rhs_)
131
- projection.within?(factory.convert(rhs_).projection)
131
+ projection.within?(factory.coerce(rhs_).projection)
132
132
  end
133
133
 
134
134
 
135
135
  def contains?(rhs_)
136
- projection.contains?(factory.convert(rhs_).projection)
136
+ projection.contains?(factory.coerce(rhs_).projection)
137
137
  end
138
138
 
139
139
 
140
140
  def overlaps?(rhs_)
141
- projection.overlaps?(factory.convert(rhs_).projection)
141
+ projection.overlaps?(factory.coerce(rhs_).projection)
142
142
  end
143
143
 
144
144
 
145
145
  def relate(rhs_, pattern_)
146
- projection.relate(factory.convert(rhs_).projection, pattern_)
146
+ projection.relate(factory.coerce(rhs_).projection, pattern_)
147
147
  end
148
148
 
149
149
 
150
150
  def distance(rhs_)
151
- projection.distance(factory.convert(rhs_).projection) / scaling_factor
151
+ projection.distance(factory.coerce(rhs_).projection) / scaling_factor
152
152
  end
153
153
 
154
154
 
@@ -163,22 +163,22 @@ module RGeo
163
163
 
164
164
 
165
165
  def intersection(rhs_)
166
- factory.unproject(projection.intersection(factory.convert(rhs_).projection))
166
+ factory.unproject(projection.intersection(factory.coerce(rhs_).projection))
167
167
  end
168
168
 
169
169
 
170
170
  def union(rhs_)
171
- factory.unproject(projection.union(factory.convert(rhs_).projection))
171
+ factory.unproject(projection.union(factory.coerce(rhs_).projection))
172
172
  end
173
173
 
174
174
 
175
175
  def difference(rhs_)
176
- factory.unproject(projection.difference(factory.convert(rhs_).projection))
176
+ factory.unproject(projection.difference(factory.coerce(rhs_).projection))
177
177
  end
178
178
 
179
179
 
180
180
  def sym_difference(rhs_)
181
- factory.unproject(projection.sym_difference(factory.convert(rhs_).projection))
181
+ factory.unproject(projection.sym_difference(factory.coerce(rhs_).projection))
182
182
  end
183
183
 
184
184
 
@@ -49,7 +49,7 @@ module RGeo
49
49
  def initialize(geography_factory_, opts_={})
50
50
  @geography_factory = geography_factory_
51
51
  if ::RGeo.const_defined?(:Geos) && Geos.supported?
52
- @projection_factory = Geos.factory(:srid => 3857, :buffer_resolution => opts_[:buffer_resolution])
52
+ @projection_factory = Geos.factory(:srid => 3857, :buffer_resolution => opts_[:buffer_resolution], :lenient_multi_polygon_assertions => opts_[:lenient_multi_polygon_assertions])
53
53
  else
54
54
  @projection_factory = nil
55
55
  end
@@ -44,6 +44,67 @@ module RGeo
44
44
  RADIUS = 6371007.2
45
45
 
46
46
 
47
+ # Represents a point on the sphere in (x,y,z) coordinates instead
48
+ # of lat-lon. This form is often faster, more convenient, and more
49
+ # numerically stable for certain computations.
50
+ #
51
+ # The coordinate system is a right-handed system where the z-axis
52
+ # goes through the north pole, the x-axis goes through the prime
53
+ # meridian, and the y-axis goes through +90 degrees longitude.
54
+ #
55
+ # This object is also used to represent a great circle, as its axis
56
+ # of rotation.
57
+
58
+ class PointXYZ
59
+
60
+ def initialize(x_, y_, z_)
61
+ r_ = ::Math.sqrt(x_ * x_ + y_ * y_ + z_ * z_)
62
+ @x = x_ / r_
63
+ @y = y_ / r_
64
+ @z = z_ / r_
65
+ end
66
+
67
+
68
+ attr_reader :x
69
+ attr_reader :y
70
+ attr_reader :z
71
+
72
+
73
+ def latlon
74
+ lat_rad_ = ::Math.asin(@z)
75
+ lon_rad_ = ::Math.atan2(@y, @x) rescue 0.0
76
+ rpd_ = Common::Helper::RADIANS_PER_DEGREE
77
+ [lat_rad_ / rpd_, lon_rad_ / rpd_]
78
+ end
79
+
80
+
81
+ def *(rhs_)
82
+ @x * rhs_.x + @y * rhs_.y + @z * rhs_.z
83
+ end
84
+
85
+
86
+ def %(rhs_)
87
+ rx_ = rhs_.x
88
+ ry_ = rhs_.y
89
+ rz_ = rhs_.z
90
+ PointXYZ.new(@y*rz_-@z*ry_, @z*rx_-@x*rz_, @x*ry_-@y-rx_) rescue nil
91
+ end
92
+
93
+
94
+ def self.from_latlon(lat_, lon_)
95
+ rpd_ = Common::Helper::RADIANS_PER_DEGREE
96
+ lat_rad_ = rpd_ * lat_
97
+ lon_rad_ = rpd_ * lon_
98
+ z_ = ::Math.sin(lat_rad_)
99
+ r_ = ::Math.cos(lat_rad_)
100
+ x_ = ::Math.cos(lon_rad_) * r_
101
+ y_ = ::Math.sin(lon_rad_) * r_
102
+ new(x_, y_, z_)
103
+ end
104
+
105
+ end
106
+
107
+
47
108
  module Calculations
48
109
 
49
110
 
@@ -65,6 +65,11 @@ module RGeo
65
65
  end
66
66
 
67
67
 
68
+ def xyz
69
+ @xyz ||= PointXYZ.from_latlon(@y, @x)
70
+ end
71
+
72
+
68
73
  def distance(rhs_)
69
74
  case rhs_
70
75
  when Features::Point