rgeo 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
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