rgeo 2.3.0 → 3.0.0.pre.rc.1

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