rgeo 2.3.0 → 3.0.0.pre.rc.1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/README.md +1 -0
  4. data/ext/geos_c_impl/analysis.c +8 -6
  5. data/ext/geos_c_impl/analysis.h +1 -3
  6. data/ext/geos_c_impl/errors.c +10 -8
  7. data/ext/geos_c_impl/errors.h +7 -3
  8. data/ext/geos_c_impl/extconf.rb +3 -0
  9. data/ext/geos_c_impl/factory.c +251 -182
  10. data/ext/geos_c_impl/factory.h +43 -62
  11. data/ext/geos_c_impl/geometry.c +56 -24
  12. data/ext/geos_c_impl/geometry.h +8 -3
  13. data/ext/geos_c_impl/geometry_collection.c +41 -148
  14. data/ext/geos_c_impl/geometry_collection.h +1 -14
  15. data/ext/geos_c_impl/globals.c +91 -0
  16. data/ext/geos_c_impl/globals.h +45 -0
  17. data/ext/geos_c_impl/line_string.c +28 -29
  18. data/ext/geos_c_impl/line_string.h +1 -3
  19. data/ext/geos_c_impl/main.c +10 -9
  20. data/ext/geos_c_impl/point.c +9 -8
  21. data/ext/geos_c_impl/point.h +1 -3
  22. data/ext/geos_c_impl/polygon.c +15 -51
  23. data/ext/geos_c_impl/polygon.h +1 -3
  24. data/ext/geos_c_impl/preface.h +8 -0
  25. data/lib/rgeo/cartesian/analysis.rb +2 -2
  26. data/lib/rgeo/cartesian/calculations.rb +54 -17
  27. data/lib/rgeo/cartesian/factory.rb +0 -7
  28. data/lib/rgeo/cartesian/feature_classes.rb +66 -46
  29. data/lib/rgeo/cartesian/feature_methods.rb +56 -20
  30. data/lib/rgeo/cartesian/interface.rb +0 -6
  31. data/lib/rgeo/cartesian/planar_graph.rb +379 -0
  32. data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
  33. data/lib/rgeo/cartesian/valid_op.rb +71 -0
  34. data/lib/rgeo/cartesian.rb +3 -0
  35. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
  36. data/lib/rgeo/error.rb +15 -0
  37. data/lib/rgeo/feature/curve.rb +12 -2
  38. data/lib/rgeo/feature/geometry.rb +38 -28
  39. data/lib/rgeo/feature/geometry_collection.rb +13 -5
  40. data/lib/rgeo/feature/line_string.rb +3 -3
  41. data/lib/rgeo/feature/multi_curve.rb +6 -1
  42. data/lib/rgeo/feature/multi_surface.rb +3 -3
  43. data/lib/rgeo/feature/point.rb +4 -4
  44. data/lib/rgeo/feature/surface.rb +3 -3
  45. data/lib/rgeo/geographic/factory.rb +0 -7
  46. data/lib/rgeo/geographic/interface.rb +4 -18
  47. data/lib/rgeo/geographic/proj4_projector.rb +0 -2
  48. data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
  49. data/lib/rgeo/geographic/projected_feature_methods.rb +63 -30
  50. data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
  51. data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
  52. data/lib/rgeo/geographic/spherical_feature_methods.rb +68 -2
  53. data/lib/rgeo/geos/capi_factory.rb +21 -31
  54. data/lib/rgeo/geos/capi_feature_classes.rb +64 -11
  55. data/lib/rgeo/geos/ffi_factory.rb +0 -28
  56. data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
  57. data/lib/rgeo/geos/ffi_feature_methods.rb +53 -10
  58. data/lib/rgeo/geos/interface.rb +18 -10
  59. data/lib/rgeo/geos/zm_factory.rb +0 -12
  60. data/lib/rgeo/geos/zm_feature_methods.rb +30 -5
  61. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +18 -8
  62. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
  63. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +37 -26
  64. data/lib/rgeo/impl_helper/basic_point_methods.rb +13 -3
  65. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +8 -3
  66. data/lib/rgeo/impl_helper/valid_op.rb +354 -0
  67. data/lib/rgeo/impl_helper/validity_check.rb +138 -0
  68. data/lib/rgeo/impl_helper.rb +1 -0
  69. data/lib/rgeo/version.rb +1 -1
  70. data/lib/rgeo/wkrep/wkb_generator.rb +1 -1
  71. data/lib/rgeo/wkrep/wkt_generator.rb +6 -6
  72. metadata +30 -7
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ # -----------------------------------------------------------------------------
4
+ #
5
+ # Simple Sweepline Intersector Class
6
+ #
7
+ # -----------------------------------------------------------------------------
8
+
9
+ module RGeo
10
+ module Cartesian
11
+ # Implements a Sweepline intersector to find all intersections
12
+ # in a group of segments. The idea is to use a horizontal line starting
13
+ # at y = +Infinity that sweeps down to y = -Infinity and every time it hits
14
+ # a new line, it will check if it intersects with any of the segments
15
+ # the line currently intersects at that y value.
16
+ # This is a more simplistic implementation that uses an array to hold
17
+ # observed segments instead of a sorted BST, so performance may be significantly
18
+ # worse in the case of lots of segments overlapping in y-ranges.
19
+ class SweeplineIntersector
20
+ Event = Struct.new(:point, :segment, :is_start)
21
+ Intersection = Struct.new(:point, :s1, :s2)
22
+
23
+ def initialize(segments)
24
+ @segments = segments
25
+ end
26
+ attr_reader :segments
27
+
28
+ # Returns the "proper" intersections from the list of segments.
29
+ #
30
+ # This will only return intersections that are not the start/end or
31
+ # end/start of the 2 segments. This could be useful for finding intersections
32
+ # in a ring for example, because knowing that segments are connected in a linestring
33
+ # is not always helpful, but those are reported by default.
34
+ #
35
+ # Note: This is not the true definition of a proper intersection. A
36
+ # truly proper intersection does not include colinear intersections and
37
+ # the intersection must lie in the interior of both segments.
38
+ #
39
+ # @return [Array<RGeo::Cartesian::SweeplineIntersector::Intersection>]
40
+ def proper_intersections
41
+ return @proper_intersections if defined?(@proper_intersections)
42
+
43
+ @proper_intersections = []
44
+ intersections.each do |intersection|
45
+ s1 = intersection.s1
46
+ s2 = intersection.s2
47
+ pt = intersection.point
48
+
49
+ unless (pt == s1.s && pt == s2.e) || (pt == s1.e && pt == s2.s)
50
+ @proper_intersections << intersection
51
+ end
52
+ end
53
+ @proper_intersections
54
+ end
55
+
56
+ # Computes the intersections of the input segments.
57
+ #
58
+ # Creates an event queue from the +events+ and adds segments to the
59
+ # +observed_segments+ array while their ending event has not been popped
60
+ # from the queue.
61
+ #
62
+ # Compares the new segment from the +is_start+ event to each observed segment
63
+ # then adds it to +observed_segments+. Records any intersections in to the
64
+ # returned array.
65
+ #
66
+ # @return [Array<RGeo::Cartesian::SweeplineIntersector::Intersection>]
67
+ def intersections
68
+ return @intersections if defined?(@intersections)
69
+
70
+ @intersections = []
71
+ observed_segments = Set.new
72
+ events.each do |e|
73
+ seg = e.segment
74
+
75
+ if e.is_start
76
+ observed_segments.each do |oseg|
77
+ int_pt = seg.segment_intersection(oseg)
78
+ if int_pt
79
+ intersect = Intersection.new(int_pt, seg, oseg)
80
+ @intersections << intersect
81
+ end
82
+ end
83
+ observed_segments << seg
84
+ else
85
+ observed_segments.delete(seg)
86
+ end
87
+ end
88
+ @intersections
89
+ end
90
+
91
+ # Returns an ordered array of events from the input segments. Events
92
+ # are the start and endpoints of each segment with an is_start tag to
93
+ # indicate if this is the starting or ending event for that segment.
94
+ #
95
+ # Ordering is done by greatest-y -> smallest-x -> is_start = true.
96
+ #
97
+ # @return [Array]
98
+ def events
99
+ return @events if defined?(@events)
100
+
101
+ @events = []
102
+ segments.each do |segment|
103
+ event_pair = create_event_pair(segment)
104
+ @events.concat(event_pair)
105
+ end
106
+
107
+ @events.sort! do |a, b|
108
+ if a.point == b.point
109
+ if a.is_start
110
+ -1
111
+ else
112
+ 1
113
+ end
114
+ elsif a.point.y == b.point.y
115
+ a.point.x <=> b.point.x
116
+ else
117
+ b.point.y <=> a.point.y
118
+ end
119
+ end
120
+ @events
121
+ end
122
+
123
+ private
124
+
125
+ # Creates a pair of events from a segment
126
+ #
127
+ # @param segment [Segment]
128
+ #
129
+ # @return [Array]
130
+ def create_event_pair(segment)
131
+ s = segment.s
132
+ e = segment.e
133
+
134
+ s_event = Event.new(s, segment)
135
+ e_event = Event.new(e, segment)
136
+
137
+ if s.y > e.y || (s.y == e.y && s.x < e.x)
138
+ s_event.is_start = true
139
+ e_event.is_start = false
140
+ else
141
+ s_event.is_start = false
142
+ e_event.is_start = true
143
+ end
144
+
145
+ [s_event, e_event]
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGeo
4
+ module Cartesian
5
+ module ValidOp
6
+ include ImplHelper::ValidOp
7
+
8
+ def validity_helper
9
+ ValidOpHelpers
10
+ end
11
+ end
12
+
13
+ module ValidOpHelpers
14
+ include ImplHelper::ValidOpHelpers
15
+
16
+ module_function(*ImplHelper::ValidOpHelpers.singleton_methods) # rubocop:disable Style/AccessModifierDeclarations
17
+
18
+ module_function
19
+
20
+ # Checks that there are no invalid intersections between the components
21
+ # of a polygon.
22
+ #
23
+ # @param [RGeo::Feature::Polygon] poly
24
+ #
25
+ # @return [String] invalid_reason
26
+ def check_consistent_area(poly)
27
+ # Get set of unique coords
28
+ pts = poly.exterior_ring.coordinates.to_set
29
+ poly.interior_rings.each do |ring|
30
+ pts += ring.coordinates
31
+ end
32
+ num_points = pts.size
33
+
34
+ # if additional nodes were added, there must be an intersection
35
+ # through a boundary.
36
+ if poly.send(:graph).incident_edges.size > num_points
37
+ return Error::SELF_INTERSECTION
38
+ end
39
+
40
+ rings = [poly.exterior_ring] + poly.interior_rings
41
+ return Error::SELF_INTERSECTION if rings.uniq.size != rings.size
42
+
43
+ nil
44
+ end
45
+
46
+ # Checks that the interior of a polygon is connected.
47
+ #
48
+ # Process to do this is to walk around an interior cycle of the
49
+ # exterior shell in the polygon's geometry graph. It will keep track
50
+ # of all the nodes it visited and if that set is a superset of the
51
+ # coordinates in the exterior_ring, the interior is connected, otherwise
52
+ # it is split somewhere.
53
+ #
54
+ # @param [RGeo::Feature::Polygon] poly
55
+ #
56
+ # @return [String] invalid_reason
57
+ def check_connected_interiors(poly)
58
+ exterior_coords = poly.exterior_ring.coordinates.to_set
59
+
60
+ visited = Set.new
61
+ poly.send(:graph).geom_edges.first.exterior_edge.and_connected do |hedge|
62
+ visited << hedge.origin.coordinates
63
+ end
64
+
65
+ return Error::DISCONNECTED_INTERIOR unless exterior_coords.subset?(visited)
66
+
67
+ nil
68
+ end
69
+ end
70
+ end
71
+ end
@@ -8,8 +8,11 @@
8
8
 
9
9
  require_relative "cartesian/calculations"
10
10
  require_relative "cartesian/feature_methods"
11
+ require_relative "cartesian/valid_op"
11
12
  require_relative "cartesian/feature_classes"
12
13
  require_relative "cartesian/factory"
13
14
  require_relative "cartesian/interface"
14
15
  require_relative "cartesian/bounding_box"
15
16
  require_relative "cartesian/analysis"
17
+ require_relative "cartesian/sweepline_intersector"
18
+ require_relative "cartesian/planar_graph"
@@ -24,7 +24,7 @@ module RGeo
24
24
  return value
25
25
  end
26
26
  unless @cur_token.is_a?(TypeString)
27
- raise Error::ParseError("Found token #{@cur_token} when we expected a value")
27
+ raise Error::ParseError, "Found token #{@cur_token} when we expected a value"
28
28
  end
29
29
  type = @cur_token
30
30
  next_token
@@ -48,7 +48,7 @@ module RGeo
48
48
  when "TOWGS84"
49
49
  bursa_wolf_params = args.find_all(Numeric)
50
50
  unless bursa_wolf_params.size == 7
51
- raise Error::ParseError("Expected 7 Bursa Wolf parameters but found #{bursa_wolf_params.size}")
51
+ raise Error::ParseError, "Expected 7 Bursa Wolf parameters but found #{bursa_wolf_params.size}"
52
52
  end
53
53
  obj = WGS84ConversionInfo.create(*bursa_wolf_params)
54
54
  when "UNIT"
@@ -87,7 +87,7 @@ module RGeo
87
87
  unit = args.find_first(Unit)
88
88
  axes = args.find_all(AxisInfo)
89
89
  unless axes.size > 0
90
- raise Error::ParseError("Expected at least one AXIS in a LOCAL_CS")
90
+ raise Error::ParseError, "Expected at least one AXIS in a LOCAL_CS"
91
91
  end
92
92
  obj = LocalCoordinateSystem.create(name, local_datum, unit, axes, *args.create_optionals)
93
93
  when "GEOCCS"
@@ -97,7 +97,7 @@ module RGeo
97
97
  linear_unit = args.find_first(LinearUnit)
98
98
  axes = args.find_all(AxisInfo)
99
99
  unless axes.size == 0 || axes.size == 3
100
- raise Error::ParseError("GEOCCS must contain either 0 or 3 AXIS parameters")
100
+ raise Error::ParseError, "GEOCCS must contain either 0 or 3 AXIS parameters"
101
101
  end
102
102
  obj = GeocentricCoordinateSystem.create(name, horizontal_datum, prime_meridian, linear_unit, axes[0], axes[1], axes[2], *args.create_optionals)
103
103
  when "VERT_CS"
@@ -113,7 +113,7 @@ module RGeo
113
113
  angular_unit = args.find_first(AngularUnit)
114
114
  axes = args.find_all(AxisInfo)
115
115
  unless axes.size == 0 || axes.size == 2
116
- raise Error::ParseError("GEOGCS must contain either 0 or 2 AXIS parameters")
116
+ raise Error::ParseError, "GEOGCS must contain either 0 or 2 AXIS parameters"
117
117
  end
118
118
  obj = GeographicCoordinateSystem.create(name, angular_unit, horizontal_datum, prime_meridian, axes[0], axes[1], *args.create_optionals)
119
119
  when "PROJCS"
@@ -125,7 +125,7 @@ module RGeo
125
125
  linear_unit = args.find_first(LinearUnit)
126
126
  axes = args.find_all(AxisInfo)
127
127
  unless axes.size == 0 || axes.size == 2
128
- raise Error::ParseError("PROJCS must contain either 0 or 2 AXIS parameters")
128
+ raise Error::ParseError, "PROJCS must contain either 0 or 2 AXIS parameters"
129
129
  end
130
130
  obj = ProjectedCoordinateSystem.create(name, geographic_coordinate_system, projection, linear_unit, axes[0], axes[1], *args.create_optionals)
131
131
  else
data/lib/rgeo/error.rb CHANGED
@@ -29,5 +29,20 @@ module RGeo
29
29
  # Parsing failed
30
30
  class ParseError < RGeoError
31
31
  end
32
+
33
+ # Standard error messages from
34
+ # https://github.com/locationtech/jts/blob/0afbfb1956ec24912a8b4dc4edff0f1200442857/modules/core/src/main/java/org/locationtech/jts/operation/valid/TopologyValidationError.java#L98-L110
35
+ TOPOLOGY_VALIDATION_ERR = "Topology Validation Error"
36
+ REPEATED_POINT = "Repeated Point"
37
+ HOLE_OUTSIDE_SHELL = "Hole lies outside shell"
38
+ NESTED_HOLES = "Holes are nested"
39
+ DISCONNECTED_INTERIOR = "Interior is disconnected"
40
+ SELF_INTERSECTION = "Self-intersection"
41
+ RING_SELF_INTERSECTION = "Ring Self-intersection"
42
+ NESTED_SHELLS = "Nested shells"
43
+ DUPLICATE_RINGS = "Duplicate Rings"
44
+ TOO_FEW_POINTS = "Too few distinct points in geometry component"
45
+ INVALID_COORDINATE = "Invalid Coordinate"
46
+ UNCLOSED_RING = "Ring is not closed"
32
47
  end
33
48
  end
@@ -90,8 +90,13 @@ module RGeo
90
90
  # Returns a boolean value. Note that this is different from the SFS
91
91
  # specification, which stipulates an integer return value.
92
92
 
93
+ def closed?
94
+ raise Error::UnsupportedOperation, "Method Curve#closed? not defined."
95
+ end
96
+
93
97
  def is_closed?
94
- raise Error::UnsupportedOperation, "Method Curve#is_closed? not defined."
98
+ warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
99
+ closed?
95
100
  end
96
101
 
97
102
  # === SFS 1.1 Description
@@ -105,8 +110,13 @@ module RGeo
105
110
  # Returns a boolean value. Note that this is different from the SFS
106
111
  # specification, which stipulates an integer return value.
107
112
 
113
+ def ring?
114
+ raise Error::UnsupportedOperation, "Method Curve#ring? not defined."
115
+ end
116
+
108
117
  def is_ring?
109
- raise Error::UnsupportedOperation, "Method Curve#is_ring? not defined."
118
+ warn "The is_ring? method is deprecated, please use the ring? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
119
+ ring?
110
120
  end
111
121
  end
112
122
  end
@@ -90,7 +90,7 @@ module RGeo
90
90
  # operations on them.)
91
91
 
92
92
  def factory
93
- raise Error::UnsupportedOperation, "Method Geometry#factory not defined."
93
+ raise Error::UnsupportedOperation, "Method #{self.class}#factory not defined."
94
94
  end
95
95
 
96
96
  # === SFS 1.1 Description
@@ -105,7 +105,7 @@ module RGeo
105
105
  # point geometries, 1 for curves, and 2 for surfaces.
106
106
 
107
107
  def dimension
108
- raise Error::UnsupportedOperation, "Method Geometry#dimension not defined."
108
+ raise Error::UnsupportedOperation, "Method #{self.class}#dimension not defined."
109
109
  end
110
110
 
111
111
  # === SFS 1.1 Description
@@ -122,7 +122,7 @@ module RGeo
122
122
  # call the +type_name+ method of the returned module.
123
123
 
124
124
  def geometry_type
125
- raise Error::UnsupportedOperation, "Method Geometry#geometry_type not defined."
125
+ raise Error::UnsupportedOperation, "Method #{self.class}#geometry_type not defined."
126
126
  end
127
127
 
128
128
  # === SFS 1.1 Description
@@ -137,7 +137,7 @@ module RGeo
137
137
  # stored in either the same or some other datastore.
138
138
 
139
139
  def srid
140
- raise Error::UnsupportedOperation, "Method Geometry#srid not defined."
140
+ raise Error::UnsupportedOperation, "Method #{self.class}#srid not defined."
141
141
  end
142
142
 
143
143
  # === SFS 1.1 Description
@@ -151,7 +151,7 @@ module RGeo
151
151
  # Returns an object that supports the Geometry interface.
152
152
 
153
153
  def envelope
154
- raise Error::UnsupportedOperation, "Method Geometry#envelope not defined."
154
+ raise Error::UnsupportedOperation, "Method #{self.class}#envelope not defined."
155
155
  end
156
156
 
157
157
  # === SFS 1.1 Description
@@ -164,7 +164,7 @@ module RGeo
164
164
  # Returns an ASCII string.
165
165
 
166
166
  def as_text
167
- raise Error::UnsupportedOperation, "Method Geometry#as_text not defined."
167
+ raise Error::UnsupportedOperation, "Method #{self.class}#as_text not defined."
168
168
  end
169
169
 
170
170
  # === SFS 1.1 Description
@@ -177,7 +177,7 @@ module RGeo
177
177
  # Returns a binary string.
178
178
 
179
179
  def as_binary
180
- raise Error::UnsupportedOperation, "Method Geometry#as_binary not defined."
180
+ raise Error::UnsupportedOperation, "Method #{self.class}#as_binary not defined."
181
181
  end
182
182
 
183
183
  # === SFS 1.1 Description
@@ -191,8 +191,13 @@ module RGeo
191
191
  # Returns a boolean value. Note that this is different from the SFS
192
192
  # specification, which stipulates an integer return value.
193
193
 
194
+ def empty?
195
+ raise Error::UnsupportedOperation, "Method #{self.class}#empty? not defined."
196
+ end
197
+
194
198
  def is_empty?
195
- raise Error::UnsupportedOperation, "Method Geometry#is_empty? not defined."
199
+ warn "The is_empty? method is deprecated, please use the empty? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
200
+ empty?
196
201
  end
197
202
 
198
203
  # === SFS 1.1 Description
@@ -208,8 +213,13 @@ module RGeo
208
213
  # Returns a boolean value. Note that this is different from the SFS
209
214
  # specification, which stipulates an integer return value.
210
215
 
216
+ def simple?
217
+ raise Error::UnsupportedOperation, "Method #{self.class}#simple? not defined."
218
+ end
219
+
211
220
  def is_simple?
212
- raise Error::UnsupportedOperation, "Method Geometry#is_simple? not defined."
221
+ warn "The is_simple? method is deprecated, please use the simple? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
222
+ simple?
213
223
  end
214
224
 
215
225
  # === SFS 1.1 Description
@@ -224,7 +234,7 @@ module RGeo
224
234
  # Returns an object that supports the Geometry interface.
225
235
 
226
236
  def boundary
227
- raise Error::UnsupportedOperation, "Method Geometry#boundary not defined."
237
+ raise Error::UnsupportedOperation, "Method #{self.class}#boundary not defined."
228
238
  end
229
239
 
230
240
  # === SFS 1.1 Description
@@ -243,7 +253,7 @@ module RGeo
243
253
  # from different factories is undefined.
244
254
 
245
255
  def equals?(another_geometry)
246
- raise Error::UnsupportedOperation, "Method Geometry#equals? not defined."
256
+ raise Error::UnsupportedOperation, "Method #{self.class}#equals? not defined."
247
257
  end
248
258
 
249
259
  # === SFS 1.1 Description
@@ -262,7 +272,7 @@ module RGeo
262
272
  # from different factories is undefined.
263
273
 
264
274
  def disjoint?(another_geometry)
265
- raise Error::UnsupportedOperation, "Method Geometry#disjoint? not defined."
275
+ raise Error::UnsupportedOperation, "Method #{self.class}#disjoint? not defined."
266
276
  end
267
277
 
268
278
  # === SFS 1.1 Description
@@ -281,7 +291,7 @@ module RGeo
281
291
  # from different factories is undefined.
282
292
 
283
293
  def intersects?(another_geometry)
284
- raise Error::UnsupportedOperation, "Method Geometry#intersects? not defined."
294
+ raise Error::UnsupportedOperation, "Method #{self.class}#intersects? not defined."
285
295
  end
286
296
 
287
297
  # === SFS 1.1 Description
@@ -300,7 +310,7 @@ module RGeo
300
310
  # from different factories is undefined.
301
311
 
302
312
  def touches?(another_geometry)
303
- raise Error::UnsupportedOperation, "Method Geometry#touches? not defined."
313
+ raise Error::UnsupportedOperation, "Method #{self.class}#touches? not defined."
304
314
  end
305
315
 
306
316
  # === SFS 1.1 Description
@@ -319,7 +329,7 @@ module RGeo
319
329
  # from different factories is undefined.
320
330
 
321
331
  def crosses?(another_geometry)
322
- raise Error::UnsupportedOperation, "Method Geometry#crosses? not defined."
332
+ raise Error::UnsupportedOperation, "Method #{self.class}#crosses? not defined."
323
333
  end
324
334
 
325
335
  # === SFS 1.1 Description
@@ -338,7 +348,7 @@ module RGeo
338
348
  # from different factories is undefined.
339
349
 
340
350
  def within?(another_geometry)
341
- raise Error::UnsupportedOperation, "Method Geometry#within? not defined."
351
+ raise Error::UnsupportedOperation, "Method #{self.class}#within? not defined."
342
352
  end
343
353
 
344
354
  # === SFS 1.1 Description
@@ -357,7 +367,7 @@ module RGeo
357
367
  # from different factories is undefined.
358
368
 
359
369
  def contains?(another_geometry)
360
- raise Error::UnsupportedOperation, "Method Geometry#contains? not defined."
370
+ raise Error::UnsupportedOperation, "Method #{self.class}#contains? not defined."
361
371
  end
362
372
 
363
373
  # === SFS 1.1 Description
@@ -376,7 +386,7 @@ module RGeo
376
386
  # from different factories is undefined.
377
387
 
378
388
  def overlaps?(another_geometry)
379
- raise Error::UnsupportedOperation, "Method Geometry#overlaps? not defined."
389
+ raise Error::UnsupportedOperation, "Method #{self.class}#overlaps? not defined."
380
390
  end
381
391
 
382
392
  # === SFS 1.1 Description
@@ -402,7 +412,7 @@ module RGeo
402
412
  # from different factories is undefined.
403
413
 
404
414
  def relate?(another_geometry, _intersection_pattern_matrix_)
405
- raise Error::UnsupportedOperation, "Method Geometry#relate not defined."
415
+ raise Error::UnsupportedOperation, "Method #{self.class}#relate not defined."
406
416
  end
407
417
 
408
418
  # === SFS 1.1 Description
@@ -421,7 +431,7 @@ module RGeo
421
431
  # distance between objects from different factories is undefined.
422
432
 
423
433
  def distance(another_geometry)
424
- raise Error::UnsupportedOperation, "Method Geometry#distance not defined."
434
+ raise Error::UnsupportedOperation, "Method #{self.class}#distance not defined."
425
435
  end
426
436
 
427
437
  # === SFS 1.1 Description
@@ -436,7 +446,7 @@ module RGeo
436
446
  # Returns an object that supports the Geometry interface.
437
447
 
438
448
  def buffer(_distance_)
439
- raise Error::UnsupportedOperation, "Method Geometry#buffer not defined."
449
+ raise Error::UnsupportedOperation, "Method #{self.class}#buffer not defined."
440
450
  end
441
451
 
442
452
  # === SFS 1.1 Description
@@ -449,7 +459,7 @@ module RGeo
449
459
  # Returns an object that supports the Geometry interface.
450
460
 
451
461
  def convex_hull
452
- raise Error::UnsupportedOperation, "Method Geometry#convex_hull not defined."
462
+ raise Error::UnsupportedOperation, "Method #{self.class}#convex_hull not defined."
453
463
  end
454
464
 
455
465
  # === SFS 1.1 Description
@@ -467,7 +477,7 @@ module RGeo
467
477
  # operations on objects from different factories is undefined.
468
478
 
469
479
  def intersection(another_geometry)
470
- raise Error::UnsupportedOperation, "Method Geometry#intersection not defined."
480
+ raise Error::UnsupportedOperation, "Method #{self.class}#intersection not defined."
471
481
  end
472
482
 
473
483
  # === SFS 1.1 Description
@@ -485,7 +495,7 @@ module RGeo
485
495
  # operations on objects from different factories is undefined.
486
496
 
487
497
  def union(another_geometry)
488
- raise Error::UnsupportedOperation, "Method Geometry#union not defined."
498
+ raise Error::UnsupportedOperation, "Method #{self.class}#union not defined."
489
499
  end
490
500
 
491
501
  # === SFS 1.1 Description
@@ -503,7 +513,7 @@ module RGeo
503
513
  # operations on objects from different factories is undefined.
504
514
 
505
515
  def difference(another_geometry)
506
- raise Error::UnsupportedOperation, "Method Geometry#difference not defined."
516
+ raise Error::UnsupportedOperation, "Method #{self.class}#difference not defined."
507
517
  end
508
518
 
509
519
  # === SFS 1.1 Description
@@ -521,7 +531,7 @@ module RGeo
521
531
  # operations on objects from different factories is undefined.
522
532
 
523
533
  def sym_difference(another_geometry)
524
- raise Error::UnsupportedOperation, "Method Geometry#sym_difference not defined."
534
+ raise Error::UnsupportedOperation, "Method #{self.class}#sym_difference not defined."
525
535
  end
526
536
 
527
537
  # Returns true if this geometric object is representationally
@@ -533,7 +543,7 @@ module RGeo
533
543
  # from different factories is undefined.
534
544
 
535
545
  def rep_equals?(another_geometry)
536
- raise Error::UnsupportedOperation, "Method Geometry#rep_equals? not defined."
546
+ raise Error::UnsupportedOperation, "Method #{self.class}#rep_equals? not defined."
537
547
  end
538
548
 
539
549
  # Unions a collection of Geometry or a single Geometry
@@ -550,7 +560,7 @@ module RGeo
550
560
  # returns nil.
551
561
  #
552
562
  def unary_union
553
- raise Error::UnsupportedOperation, "Method Geometry#unary_union not defined."
563
+ raise Error::UnsupportedOperation, "Method #{self.class}#unary_union not defined."
554
564
  end
555
565
 
556
566
  # This method should behave almost the same as the rep_equals?
@@ -44,7 +44,7 @@ module RGeo
44
44
  # Returns an integer.
45
45
 
46
46
  def num_geometries
47
- raise Error::UnsupportedOperation, "Method GeometryCollection#num_geometries not defined."
47
+ raise Error::UnsupportedOperation, "Method #{self.class}#num_geometries not defined."
48
48
  end
49
49
 
50
50
  # === SFS 1.1 Description
@@ -59,7 +59,7 @@ module RGeo
59
59
  # in that it does not support negative indexes.
60
60
 
61
61
  def geometry_n(n)
62
- raise Error::UnsupportedOperation, "Method GeometryCollection#geometry_n not defined."
62
+ raise Error::UnsupportedOperation, "Method #{self.class}#geometry_n not defined."
63
63
  end
64
64
 
65
65
  # Alias of the num_geometries method.
@@ -79,13 +79,13 @@ module RGeo
79
79
  # returns nil, where [-1] returns the last element of the collection.
80
80
 
81
81
  def [](n)
82
- raise Error::UnsupportedOperation, "Method GeometryCollection#[] not defined."
82
+ raise Error::UnsupportedOperation, "Method #{self.class}#[] not defined."
83
83
  end
84
84
 
85
85
  # Nodes the linework in a list of Geometries
86
86
  #
87
87
  def node
88
- raise Error::UnsupportedOperation, "Method GeometryCollection#node not defined."
88
+ raise Error::UnsupportedOperation, "Method #{self.class}#node not defined."
89
89
  end
90
90
 
91
91
  # Iterates over the geometries of this GeometryCollection.
@@ -96,7 +96,15 @@ module RGeo
96
96
  # include the Enumerable mixin.
97
97
 
98
98
  def each(&block)
99
- raise Error::UnsupportedOperation, "Method GeometryCollection#each not defined."
99
+ raise Error::UnsupportedOperation, "Method #{self.class}#each not defined."
100
+ end
101
+
102
+ # Gives a point that is guaranteed to be within the geometry.
103
+ #
104
+ # Extends OGC SFS 1.1 and follows PostGIS standards.
105
+ # @see https://postgis.net/docs/ST_PointOnSurface.html
106
+ def point_on_surface
107
+ raise Error::UnsupportedOperation, "Method #{self.class}#each not defined."
100
108
  end
101
109
  end
102
110
  end
@@ -34,7 +34,7 @@ module RGeo
34
34
  # Returns an integer.
35
35
 
36
36
  def num_points
37
- raise Error::UnsupportedOperation, "Method LineString#num_points not defined."
37
+ raise Error::UnsupportedOperation, "Method #{self.class}#num_points not defined."
38
38
  end
39
39
 
40
40
  # === SFS 1.1 Description
@@ -48,14 +48,14 @@ module RGeo
48
48
  # Does not support negative indexes.
49
49
 
50
50
  def point_n(n)
51
- raise Error::UnsupportedOperation, "Method LineString#point_n not defined."
51
+ raise Error::UnsupportedOperation, "Method #{self.class}#point_n not defined."
52
52
  end
53
53
 
54
54
  # Returns the constituent points as an array of objects that
55
55
  # support the Point interface.
56
56
 
57
57
  def points
58
- raise Error::UnsupportedOperation, "Method LineString#points not defined."
58
+ raise Error::UnsupportedOperation, "Method #{self.class}#points not defined."
59
59
  end
60
60
  end
61
61
  end