rgeo 3.0.0.pre.rc.3 → 3.0.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.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/ext/geos_c_impl/extconf.rb +1 -0
- data/ext/geos_c_impl/factory.c +43 -5
- data/ext/geos_c_impl/factory.h +13 -2
- data/ext/geos_c_impl/geometry.c +178 -122
- data/ext/geos_c_impl/geometry_collection.c +17 -19
- data/ext/geos_c_impl/line_string.c +46 -36
- data/ext/geos_c_impl/point.c +0 -2
- data/ext/geos_c_impl/polygon.c +10 -11
- data/ext/geos_c_impl/polygon.h +1 -1
- data/ext/geos_c_impl/preface.h +3 -0
- data/ext/geos_c_impl/ruby_more.c +7 -0
- data/ext/geos_c_impl/ruby_more.h +8 -0
- data/lib/rgeo/cartesian/analysis.rb +5 -3
- data/lib/rgeo/cartesian/bounding_box.rb +74 -79
- data/lib/rgeo/cartesian/calculations.rb +20 -26
- data/lib/rgeo/cartesian/factory.rb +47 -49
- data/lib/rgeo/cartesian/planar_graph.rb +10 -16
- data/lib/rgeo/cartesian/sweepline_intersector.rb +1 -3
- data/lib/rgeo/cartesian/valid_op.rb +1 -3
- data/lib/rgeo/coord_sys/cs/entities.rb +91 -101
- data/lib/rgeo/coord_sys/cs/factories.rb +0 -2
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +70 -29
- data/lib/rgeo/feature/curve.rb +0 -1
- data/lib/rgeo/feature/factory.rb +25 -27
- data/lib/rgeo/feature/factory_generator.rb +3 -4
- data/lib/rgeo/feature/geometry.rb +41 -30
- data/lib/rgeo/feature/geometry_collection.rb +3 -4
- data/lib/rgeo/feature/line_string.rb +1 -2
- data/lib/rgeo/feature/linear_ring.rb +0 -1
- data/lib/rgeo/feature/multi_curve.rb +0 -1
- data/lib/rgeo/feature/multi_surface.rb +0 -1
- data/lib/rgeo/feature/point.rb +0 -1
- data/lib/rgeo/feature/polygon.rb +1 -2
- data/lib/rgeo/feature/surface.rb +0 -1
- data/lib/rgeo/feature/types.rb +69 -85
- data/lib/rgeo/geographic/factory.rb +87 -80
- data/lib/rgeo/geographic/interface.rb +44 -27
- data/lib/rgeo/geographic/projected_feature_methods.rb +2 -6
- data/lib/rgeo/geographic/projected_window.rb +35 -21
- data/lib/rgeo/geographic/simple_mercator_projector.rb +27 -15
- data/lib/rgeo/geographic/spherical_feature_methods.rb +8 -3
- data/lib/rgeo/geographic/spherical_math.rb +17 -20
- data/lib/rgeo/geos/capi_factory.rb +50 -50
- data/lib/rgeo/geos/ffi_factory.rb +50 -49
- data/lib/rgeo/geos/ffi_feature_methods.rb +72 -98
- data/lib/rgeo/geos/interface.rb +16 -16
- data/lib/rgeo/geos/utils.rb +5 -5
- data/lib/rgeo/geos/zm_factory.rb +50 -42
- data/lib/rgeo/geos/zm_feature_methods.rb +15 -9
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -2
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +18 -24
- data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -3
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +15 -16
- data/lib/rgeo/impl_helper/utils.rb +3 -9
- data/lib/rgeo/impl_helper/valid_op.rb +12 -16
- data/lib/rgeo/version.rb +1 -1
- data/lib/rgeo/wkrep/wkb_generator.rb +42 -47
- data/lib/rgeo/wkrep/wkb_parser.rb +17 -18
- data/lib/rgeo/wkrep/wkt_generator.rb +23 -16
- data/lib/rgeo/wkrep/wkt_parser.rb +23 -13
- metadata +6 -6
data/lib/rgeo/geos/zm_factory.rb
CHANGED
@@ -9,7 +9,6 @@
|
|
9
9
|
module RGeo
|
10
10
|
module Geos
|
11
11
|
# A factory for Geos that handles both Z and M.
|
12
|
-
|
13
12
|
class ZMFactory
|
14
13
|
include Feature::Factory::Instance
|
15
14
|
include ImplHelper::Utils
|
@@ -60,33 +59,37 @@ module RGeo
|
|
60
59
|
end
|
61
60
|
|
62
61
|
wkt_generator = opts[:wkt_generator]
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
62
|
+
@wkt_generator =
|
63
|
+
case wkt_generator
|
64
|
+
when Hash
|
65
|
+
WKRep::WKTGenerator.new(wkt_generator)
|
66
|
+
else
|
67
|
+
WKRep::WKTGenerator.new(convert_case: :upper)
|
68
|
+
end
|
69
69
|
wkb_generator = opts[:wkb_generator]
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
70
|
+
@wkb_generator =
|
71
|
+
case wkb_generator
|
72
|
+
when Hash
|
73
|
+
WKRep::WKBGenerator.new(wkb_generator)
|
74
|
+
else
|
75
|
+
WKRep::WKBGenerator.new
|
76
|
+
end
|
76
77
|
wkt_parser = opts[:wkt_parser]
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
@wkt_parser =
|
79
|
+
case wkt_parser
|
80
|
+
when Hash
|
81
|
+
WKRep::WKTParser.new(self, wkt_parser)
|
82
|
+
else
|
83
|
+
WKRep::WKTParser.new(self)
|
84
|
+
end
|
83
85
|
wkb_parser = opts[:wkb_parser]
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
86
|
+
@wkb_parser =
|
87
|
+
case wkb_parser
|
88
|
+
when Hash
|
89
|
+
WKRep::WKBParser.new(self, wkb_parser)
|
90
|
+
else
|
91
|
+
WKRep::WKBParser.new(self)
|
92
|
+
end
|
90
93
|
end
|
91
94
|
|
92
95
|
# Marshal support
|
@@ -108,11 +111,9 @@ module RGeo
|
|
108
111
|
end
|
109
112
|
|
110
113
|
def marshal_load(data) # :nodoc:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
coord_sys = nil
|
115
|
-
end
|
114
|
+
cs_class = CoordSys::CONFIG.default_coord_sys_class
|
115
|
+
coord_sys = data["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
|
116
|
+
|
116
117
|
initialize(
|
117
118
|
native_interface: (data["nffi"] ? :ffi : :capi),
|
118
119
|
has_z_coordinate: data["hasz"],
|
@@ -139,17 +140,16 @@ module RGeo
|
|
139
140
|
coder["wkb_parser"] = @wkb_parser.properties
|
140
141
|
coder["auto_prepare"] = @zfactory.property(:auto_prepare).to_s
|
141
142
|
coder["native_interface"] = @zfactory.is_a?(FFIFactory) ? "ffi" : "capi"
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
|
144
|
+
return unless (coord_sys = @zfactory.coord_sys)
|
145
|
+
|
146
|
+
coder["coord_sys"] = coord_sys.to_wkt
|
145
147
|
end
|
146
148
|
|
147
149
|
def init_with(coder) # :nodoc:
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
coord_sys = nil
|
152
|
-
end
|
150
|
+
cs_class = CoordSys::CONFIG.default_coord_sys_class
|
151
|
+
coord_sys = coder["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
|
152
|
+
|
153
153
|
initialize(
|
154
154
|
native_interface: coder["native_interface"] == "ffi" ? :ffi : :capi,
|
155
155
|
has_z_coordinate: coder["has_z_coordinate"],
|
@@ -192,8 +192,8 @@ module RGeo
|
|
192
192
|
|
193
193
|
# Factory equivalence test.
|
194
194
|
|
195
|
-
def eql?(
|
196
|
-
|
195
|
+
def eql?(other)
|
196
|
+
other.is_a?(ZMFactory) && other.z_factory == @zfactory
|
197
197
|
end
|
198
198
|
alias == eql?
|
199
199
|
|
@@ -227,7 +227,11 @@ module RGeo
|
|
227
227
|
# See RGeo::Feature::Factory#point
|
228
228
|
|
229
229
|
def point(x, y, z = 0, m = 0)
|
230
|
-
create_feature(
|
230
|
+
create_feature(
|
231
|
+
ZMPointImpl,
|
232
|
+
@zfactory.point(x, y, z),
|
233
|
+
@mfactory.point(x, y, m)
|
234
|
+
)
|
231
235
|
end
|
232
236
|
|
233
237
|
# See RGeo::Feature::Factory#line_string
|
@@ -251,7 +255,11 @@ module RGeo
|
|
251
255
|
# See RGeo::Feature::Factory#polygon
|
252
256
|
|
253
257
|
def polygon(outer_ring, inner_rings = nil)
|
254
|
-
create_feature(
|
258
|
+
create_feature(
|
259
|
+
ZMPolygonImpl,
|
260
|
+
@zfactory.polygon(outer_ring, inner_rings),
|
261
|
+
@mfactory.polygon(outer_ring, inner_rings)
|
262
|
+
)
|
255
263
|
end
|
256
264
|
|
257
265
|
# See RGeo::Feature::Factory#collection
|
@@ -128,7 +128,6 @@ module RGeo
|
|
128
128
|
def relate?(rhs, pattern)
|
129
129
|
@zgeometry.relate?(RGeo::Feature.cast(rhs, self).z_geometry, pattern)
|
130
130
|
end
|
131
|
-
alias relate relate? # DEPRECATED
|
132
131
|
|
133
132
|
def distance(rhs)
|
134
133
|
@zgeometry.distance(RGeo::Feature.cast(rhs, self).z_geometry)
|
@@ -159,12 +158,19 @@ module RGeo
|
|
159
158
|
|
160
159
|
def sym_difference(rhs)
|
161
160
|
rhs = RGeo::Feature.cast(rhs, self)
|
162
|
-
@factory.create_feature(
|
161
|
+
@factory.create_feature(
|
162
|
+
nil,
|
163
|
+
@zgeometry.sym_difference(rhs.z_geometry),
|
164
|
+
@mgeometry.sym_difference(rhs.m_geometry)
|
165
|
+
)
|
163
166
|
end
|
164
167
|
|
165
168
|
def rep_equals?(rhs)
|
166
169
|
rhs = RGeo::Feature.cast(rhs, self)
|
167
|
-
rhs.is_a?(self.class) &&
|
170
|
+
rhs.is_a?(self.class) &&
|
171
|
+
@factory.eql?(rhs.factory) &&
|
172
|
+
@zgeometry.rep_equals?(rhs.z_geometry) &&
|
173
|
+
@mgeometry.rep_equals?(rhs.m_geometry)
|
168
174
|
end
|
169
175
|
|
170
176
|
alias eql? rep_equals?
|
@@ -250,8 +256,8 @@ module RGeo
|
|
250
256
|
@zgeometry.num_points
|
251
257
|
end
|
252
258
|
|
253
|
-
def point_n(
|
254
|
-
@factory.create_feature(ZMPointImpl, @zgeometry.point_n(
|
259
|
+
def point_n(idx)
|
260
|
+
@factory.create_feature(ZMPointImpl, @zgeometry.point_n(idx), @mgeometry.point_n(idx))
|
255
261
|
end
|
256
262
|
|
257
263
|
def points
|
@@ -290,8 +296,8 @@ module RGeo
|
|
290
296
|
@zgeometry.num_interior_rings
|
291
297
|
end
|
292
298
|
|
293
|
-
def interior_ring_n(
|
294
|
-
@factory.create_feature(ZMLineStringImpl, @zgeometry.interior_ring_n(
|
299
|
+
def interior_ring_n(idx)
|
300
|
+
@factory.create_feature(ZMLineStringImpl, @zgeometry.interior_ring_n(idx), @mgeometry.interior_ring_n(idx))
|
295
301
|
end
|
296
302
|
|
297
303
|
def interior_rings
|
@@ -315,8 +321,8 @@ module RGeo
|
|
315
321
|
end
|
316
322
|
alias size num_geometries
|
317
323
|
|
318
|
-
def geometry_n(
|
319
|
-
@factory.create_feature(nil, @zgeometry.geometry_n(
|
324
|
+
def geometry_n(idx)
|
325
|
+
@factory.create_feature(nil, @zgeometry.geometry_n(idx), @mgeometry.geometry_n(idx))
|
320
326
|
end
|
321
327
|
alias [] geometry_n
|
322
328
|
|
@@ -27,12 +27,12 @@ module RGeo
|
|
27
27
|
@elements.size
|
28
28
|
end
|
29
29
|
|
30
|
-
def geometry_n(
|
31
|
-
|
30
|
+
def geometry_n(idx)
|
31
|
+
idx < 0 ? nil : @elements[idx]
|
32
32
|
end
|
33
33
|
|
34
|
-
def [](
|
35
|
-
@elements[
|
34
|
+
def [](idx)
|
35
|
+
@elements[idx]
|
36
36
|
end
|
37
37
|
|
38
38
|
def each(&block)
|
@@ -19,9 +19,7 @@ module RGeo
|
|
19
19
|
# LineStrings in general need to check that there's not one point
|
20
20
|
# GEOS doesn't allow instantiation of single point LineStrings so
|
21
21
|
# we should handle it.
|
22
|
-
if @points.size == 1
|
23
|
-
raise Error::InvalidGeometry, "LineString Cannot Have 1 Point"
|
24
|
-
end
|
22
|
+
raise Error::InvalidGeometry, "LineString Cannot Have 1 Point" if @points.size == 1
|
25
23
|
init_geometry
|
26
24
|
end
|
27
25
|
|
@@ -29,8 +27,8 @@ module RGeo
|
|
29
27
|
@points.size
|
30
28
|
end
|
31
29
|
|
32
|
-
def point_n(
|
33
|
-
|
30
|
+
def point_n(idx)
|
31
|
+
idx < 0 ? nil : @points[idx]
|
34
32
|
end
|
35
33
|
|
36
34
|
def points
|
@@ -64,10 +62,9 @@ module RGeo
|
|
64
62
|
end
|
65
63
|
|
66
64
|
def closed?
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@closed
|
65
|
+
return @closed if defined?(@closed)
|
66
|
+
|
67
|
+
@closed = @points.size > 2 && @points.first == @points.last
|
71
68
|
end
|
72
69
|
|
73
70
|
def ring?
|
@@ -111,15 +108,15 @@ module RGeo
|
|
111
108
|
def point_intersect_segment?(point, start_point, end_point)
|
112
109
|
return false unless point_collinear?(point, start_point, end_point)
|
113
110
|
|
114
|
-
if start_point.x
|
115
|
-
between_coordinate?(point.x, start_point.x, end_point.x)
|
116
|
-
else
|
111
|
+
if start_point.x == end_point.x
|
117
112
|
between_coordinate?(point.y, start_point.y, end_point.y)
|
113
|
+
else
|
114
|
+
between_coordinate?(point.x, start_point.x, end_point.x)
|
118
115
|
end
|
119
116
|
end
|
120
117
|
|
121
|
-
def point_collinear?(
|
122
|
-
(
|
118
|
+
def point_collinear?(pt1, pt2, pt3)
|
119
|
+
(pt2.x - pt1.x) * (pt3.y - pt1.y) == (pt3.x - pt1.x) * (pt2.y - pt1.y)
|
123
120
|
end
|
124
121
|
|
125
122
|
def between_coordinate?(coord, start_coord, end_coord)
|
@@ -137,9 +134,7 @@ module RGeo
|
|
137
134
|
def initialize(factory, start, stop)
|
138
135
|
self.factory = factory
|
139
136
|
cstart = Feature.cast(start, factory, Feature::Point)
|
140
|
-
unless cstart
|
141
|
-
raise Error::InvalidGeometry, "Could not cast start: #{start}"
|
142
|
-
end
|
137
|
+
raise Error::InvalidGeometry, "Could not cast start: #{start}" unless cstart
|
143
138
|
cstop = Feature.cast(stop, factory, Feature::Point)
|
144
139
|
raise Error::InvalidGeometry, "Could not cast end: #{stop}" unless cstop
|
145
140
|
@points = [cstart, cstop]
|
@@ -158,9 +153,7 @@ module RGeo
|
|
158
153
|
module BasicLinearRingMethods # :nodoc:
|
159
154
|
def initialize(factory, points)
|
160
155
|
super
|
161
|
-
|
162
|
-
raise Error::InvalidGeometry, "LinearRings must have 0 or >= 4 points"
|
163
|
-
end
|
156
|
+
raise Error::InvalidGeometry, "LinearRings must have 0 or >= 4 points" if @points.size.between?(1, 3)
|
164
157
|
end
|
165
158
|
|
166
159
|
def geometry_type
|
@@ -176,10 +169,11 @@ module RGeo
|
|
176
169
|
# Close ring if necessary.
|
177
170
|
def init_geometry
|
178
171
|
super
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
172
|
+
|
173
|
+
return if @points.empty?
|
174
|
+
|
175
|
+
@points << @points.first if @points.first != @points.last
|
176
|
+
@points = @points.chunk { |x| x }.map(&:first)
|
183
177
|
end
|
184
178
|
end
|
185
179
|
end
|
@@ -15,9 +15,7 @@ module RGeo
|
|
15
15
|
@y = y.to_f
|
16
16
|
@z = factory.property(:has_z_coordinate) ? extra.shift.to_f : nil
|
17
17
|
@m = factory.property(:has_m_coordinate) ? extra.shift.to_f : nil
|
18
|
-
|
19
|
-
raise ArgumentError, "Too many arguments for point initializer"
|
20
|
-
end
|
18
|
+
raise ArgumentError, "Too many arguments for point initializer" unless extra.empty?
|
21
19
|
init_geometry
|
22
20
|
end
|
23
21
|
|
@@ -12,14 +12,10 @@ module RGeo
|
|
12
12
|
def initialize(factory, exterior_ring, interior_rings)
|
13
13
|
self.factory = factory
|
14
14
|
@exterior_ring = Feature.cast(exterior_ring, factory, Feature::LinearRing)
|
15
|
-
unless @exterior_ring
|
16
|
-
raise Error::InvalidGeometry, "Failed to cast exterior ring #{exterior_ring}"
|
17
|
-
end
|
15
|
+
raise Error::InvalidGeometry, "Failed to cast exterior ring #{exterior_ring}" unless @exterior_ring
|
18
16
|
@interior_rings = (interior_rings || []).map do |elem|
|
19
17
|
elem = Feature.cast(elem, factory, Feature::LinearRing)
|
20
|
-
unless elem
|
21
|
-
raise Error::InvalidGeometry, "Could not cast interior ring #{elem}"
|
22
|
-
end
|
18
|
+
raise Error::InvalidGeometry, "Could not cast interior ring #{elem}" unless elem
|
23
19
|
elem
|
24
20
|
end
|
25
21
|
init_geometry
|
@@ -33,8 +29,8 @@ module RGeo
|
|
33
29
|
@interior_rings.size
|
34
30
|
end
|
35
31
|
|
36
|
-
def interior_ring_n(
|
37
|
-
|
32
|
+
def interior_ring_n(idx)
|
33
|
+
idx < 0 ? nil : @interior_rings[idx]
|
38
34
|
end
|
39
35
|
|
40
36
|
def interior_rings
|
@@ -61,11 +57,14 @@ module RGeo
|
|
61
57
|
end
|
62
58
|
|
63
59
|
def rep_equals?(rhs)
|
64
|
-
|
65
|
-
rhs.
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
proper_match = rhs.is_a?(self.class) &&
|
61
|
+
rhs.factory.eql?(@factory) &&
|
62
|
+
@exterior_ring.rep_equals?(rhs.exterior_ring) &&
|
63
|
+
@interior_rings.size == rhs.num_interior_rings
|
64
|
+
|
65
|
+
return false unless proper_match
|
66
|
+
|
67
|
+
rhs.interior_rings.each_with_index { |r, i| return false unless @interior_rings[i].rep_equals?(r) }
|
69
68
|
end
|
70
69
|
|
71
70
|
def hash
|
@@ -80,7 +79,8 @@ module RGeo
|
|
80
79
|
if Feature::Point === rhs
|
81
80
|
contains_point?(rhs)
|
82
81
|
else
|
83
|
-
raise(
|
82
|
+
raise(
|
83
|
+
Error::UnsupportedOperation,
|
84
84
|
"Method Polygon#contains? is only defined for Point"
|
85
85
|
)
|
86
86
|
end
|
@@ -90,7 +90,7 @@ module RGeo
|
|
90
90
|
|
91
91
|
def contains_point?(point)
|
92
92
|
ring_encloses_point?(@exterior_ring, point) &&
|
93
|
-
|
93
|
+
@interior_rings.none? do |exclusion|
|
94
94
|
ring_encloses_point?(exclusion, point, on_border_return: true)
|
95
95
|
end
|
96
96
|
end
|
@@ -114,7 +114,6 @@ module RGeo
|
|
114
114
|
encloses_point
|
115
115
|
end
|
116
116
|
|
117
|
-
|
118
117
|
def copy_state_from(obj)
|
119
118
|
super
|
120
119
|
@exterior_ring = obj.exterior_ring
|
@@ -18,20 +18,14 @@ module RGeo
|
|
18
18
|
# multiple times with different values and others pass the data
|
19
19
|
# to a CAPI or FFI.
|
20
20
|
def self.setup_coord_sys(srid, coord_sys, coord_sys_class)
|
21
|
-
unless coord_sys_class.is_a?(Class)
|
22
|
-
coord_sys_class = CoordSys::CONFIG.default_coord_sys_class
|
23
|
-
end
|
21
|
+
coord_sys_class = CoordSys::CONFIG.default_coord_sys_class unless coord_sys_class.is_a?(Class)
|
24
22
|
|
25
|
-
if coord_sys.is_a?(String)
|
26
|
-
coord_sys = coord_sys_class.create_from_wkt(coord_sys)
|
27
|
-
end
|
23
|
+
coord_sys = coord_sys_class.create_from_wkt(coord_sys) if coord_sys.is_a?(String)
|
28
24
|
|
29
25
|
srid ||= coord_sys.authority_code if coord_sys
|
30
26
|
srid = srid.to_i
|
31
27
|
# Create a coord sys based on the SRID if one was not given
|
32
|
-
if coord_sys.nil? && srid != 0
|
33
|
-
coord_sys = coord_sys_class.create(srid)
|
34
|
-
end
|
28
|
+
coord_sys = coord_sys_class.create(srid) if coord_sys.nil? && srid != 0
|
35
29
|
|
36
30
|
{ coord_sys: coord_sys, srid: srid }
|
37
31
|
end
|
@@ -181,12 +181,12 @@ module RGeo
|
|
181
181
|
|
182
182
|
# Checks that the given point has valid coordinates.
|
183
183
|
#
|
184
|
-
# @param
|
184
|
+
# @param point [RGeo::Feature::Point]
|
185
185
|
#
|
186
186
|
# @return [String] invalid_reason
|
187
|
-
def check_invalid_coordinate(
|
188
|
-
x =
|
189
|
-
y =
|
187
|
+
def check_invalid_coordinate(point)
|
188
|
+
x = point.x
|
189
|
+
y = point.y
|
190
190
|
return if x.finite? && y.finite? && x.real? && y.real?
|
191
191
|
|
192
192
|
Error::INVALID_COORDINATE
|
@@ -265,9 +265,7 @@ module RGeo
|
|
265
265
|
|
266
266
|
poly.interior_rings.each do |interior|
|
267
267
|
test_pt = interior.start_point
|
268
|
-
unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt)
|
269
|
-
return Error::HOLE_OUTSIDE_SHELL
|
270
|
-
end
|
268
|
+
return Error::HOLE_OUTSIDE_SHELL unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt)
|
271
269
|
end
|
272
270
|
|
273
271
|
nil
|
@@ -322,27 +320,25 @@ module RGeo
|
|
322
320
|
|
323
321
|
# Checks that polygons do not intersect in a multipolygon.
|
324
322
|
#
|
325
|
-
# @param
|
323
|
+
# @param mpoly [RGeo::Feature::MultiPolygon]
|
326
324
|
#
|
327
325
|
# @return [String] invalid_reason
|
328
|
-
def check_consistent_area_mp(
|
329
|
-
|
330
|
-
if p1.exterior_ring.crosses?(p2.exterior_ring)
|
331
|
-
return Error::SELF_INTERSECTION
|
332
|
-
end
|
326
|
+
def check_consistent_area_mp(mpoly)
|
327
|
+
mpoly.geometries.combination(2) do |p1, p2|
|
328
|
+
return Error::SELF_INTERSECTION if p1.exterior_ring.crosses?(p2.exterior_ring)
|
333
329
|
end
|
334
330
|
nil
|
335
331
|
end
|
336
332
|
|
337
333
|
# Checks that individual polygons within a multipolygon are not nested.
|
338
334
|
#
|
339
|
-
# @param
|
335
|
+
# @param mpoly [RGeo::Feature::MultiPolygon]
|
340
336
|
#
|
341
337
|
# @return [String] invalid_reason
|
342
|
-
def check_shells_not_nested(
|
338
|
+
def check_shells_not_nested(mpoly)
|
343
339
|
# Since we've passed the consistent area test, we can just check
|
344
340
|
# that one point lies in the other.
|
345
|
-
|
341
|
+
mpoly.geometries.combination(2) do |p1, p2|
|
346
342
|
if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point)
|
347
343
|
return Error::NESTED_SHELLS
|
348
344
|
end
|
data/lib/rgeo/version.rb
CHANGED
@@ -39,7 +39,6 @@ module RGeo
|
|
39
39
|
# [<tt>:little_endian</tt>]
|
40
40
|
# If true, output little endian (NDR) byte order. If false, output
|
41
41
|
# big endian (XDR), or network byte order. Default is false.
|
42
|
-
|
43
42
|
class WKBGenerator
|
44
43
|
# :stopdoc:
|
45
44
|
TYPE_CODES = {
|
@@ -107,7 +106,7 @@ module RGeo
|
|
107
106
|
has_m = false
|
108
107
|
end
|
109
108
|
result = Result.new(has_z, has_m)
|
110
|
-
generate_feature(obj, result, true)
|
109
|
+
generate_feature(obj, result, toplevel: true)
|
111
110
|
result.emit(@hex_format)
|
112
111
|
end
|
113
112
|
|
@@ -126,7 +125,7 @@ module RGeo
|
|
126
125
|
|
127
126
|
def emit(hex_format)
|
128
127
|
str = @buffer.join
|
129
|
-
hex_format ? str.
|
128
|
+
hex_format ? str.unpack1("H*") : str
|
130
129
|
end
|
131
130
|
|
132
131
|
def z?
|
@@ -139,79 +138,75 @@ module RGeo
|
|
139
138
|
end
|
140
139
|
private_constant :Result
|
141
140
|
|
142
|
-
def emit_byte(value,
|
143
|
-
|
141
|
+
def emit_byte(value, rval)
|
142
|
+
rval << [value].pack("C")
|
144
143
|
end
|
145
144
|
|
146
|
-
def emit_integer(value,
|
147
|
-
|
145
|
+
def emit_integer(value, rval)
|
146
|
+
rval << [value].pack(@little_endian ? "V" : "N")
|
148
147
|
end
|
149
148
|
|
150
|
-
def emit_doubles(array,
|
151
|
-
|
149
|
+
def emit_doubles(array, rval)
|
150
|
+
rval << array.pack(@little_endian ? "E*" : "G*")
|
152
151
|
end
|
153
152
|
|
154
|
-
def emit_line_string_coords(obj,
|
153
|
+
def emit_line_string_coords(obj, rval)
|
155
154
|
array = []
|
156
|
-
obj.points.each { |pt| point_coords(pt,
|
157
|
-
emit_integer(obj.num_points,
|
158
|
-
emit_doubles(array,
|
155
|
+
obj.points.each { |pt| point_coords(pt, rval, array) }
|
156
|
+
emit_integer(obj.num_points, rval)
|
157
|
+
emit_doubles(array, rval)
|
159
158
|
end
|
160
159
|
|
161
|
-
def point_coords(obj,
|
160
|
+
def point_coords(obj, rval, array = [])
|
162
161
|
array << obj.x
|
163
162
|
array << obj.y
|
164
|
-
array << obj.z if
|
165
|
-
array << obj.m if
|
163
|
+
array << obj.z if rval.z?
|
164
|
+
array << obj.m if rval.m?
|
166
165
|
array
|
167
166
|
end
|
168
167
|
|
169
|
-
def generate_feature(obj,
|
170
|
-
emit_byte(@little_endian ? 1 : 0,
|
168
|
+
def generate_feature(obj, rval, toplevel: false)
|
169
|
+
emit_byte(@little_endian ? 1 : 0, rval)
|
171
170
|
type = obj.geometry_type
|
172
171
|
type_code = TYPE_CODES[type]
|
173
|
-
unless type_code
|
174
|
-
raise Error::ParseError, "Unrecognized Geometry Type: #{type}"
|
175
|
-
end
|
172
|
+
raise Error::ParseError, "Unrecognized Geometry Type: #{type}" unless type_code
|
176
173
|
emit_srid = false
|
177
|
-
|
178
|
-
|
179
|
-
type_code |=
|
174
|
+
case @type_format
|
175
|
+
when :ewkb
|
176
|
+
type_code |= 0x80000000 if rval.z?
|
177
|
+
type_code |= 0x40000000 if rval.m?
|
180
178
|
if @emit_ewkb_srid && toplevel
|
181
179
|
type_code |= 0x20000000
|
182
180
|
emit_srid = true
|
183
181
|
end
|
184
|
-
|
185
|
-
type_code += 1000 if
|
186
|
-
type_code += 2000 if
|
182
|
+
when :wkb12
|
183
|
+
type_code += 1000 if rval.z?
|
184
|
+
type_code += 2000 if rval.m?
|
187
185
|
end
|
188
|
-
emit_integer(type_code,
|
189
|
-
emit_integer(obj.srid,
|
186
|
+
emit_integer(type_code, rval)
|
187
|
+
emit_integer(obj.srid, rval) if emit_srid
|
188
|
+
type_is_collection = [
|
189
|
+
Feature::GeometryCollection,
|
190
|
+
Feature::MultiPoint,
|
191
|
+
Feature::MultiLineString,
|
192
|
+
Feature::MultiPolygon
|
193
|
+
].include?(type)
|
190
194
|
if type == Feature::Point
|
191
|
-
emit_doubles(point_coords(obj,
|
195
|
+
emit_doubles(point_coords(obj, rval), rval)
|
192
196
|
elsif type.subtype_of?(Feature::LineString)
|
193
|
-
emit_line_string_coords(obj,
|
197
|
+
emit_line_string_coords(obj, rval)
|
194
198
|
elsif type == Feature::Polygon
|
195
199
|
exterior_ring = obj.exterior_ring
|
196
200
|
if exterior_ring.empty?
|
197
|
-
emit_integer(0,
|
201
|
+
emit_integer(0, rval)
|
198
202
|
else
|
199
|
-
emit_integer(1 + obj.num_interior_rings,
|
200
|
-
emit_line_string_coords(exterior_ring,
|
201
|
-
obj.interior_rings.each { |r| emit_line_string_coords(r,
|
203
|
+
emit_integer(1 + obj.num_interior_rings, rval)
|
204
|
+
emit_line_string_coords(exterior_ring, rval)
|
205
|
+
obj.interior_rings.each { |r| emit_line_string_coords(r, rval) }
|
202
206
|
end
|
203
|
-
elsif
|
204
|
-
emit_integer(obj.num_geometries,
|
205
|
-
obj.each { |g| generate_feature(g,
|
206
|
-
elsif type == Feature::MultiPoint
|
207
|
-
emit_integer(obj.num_geometries, rv)
|
208
|
-
obj.each { |g| generate_feature(g, rv) }
|
209
|
-
elsif type == Feature::MultiLineString
|
210
|
-
emit_integer(obj.num_geometries, rv)
|
211
|
-
obj.each { |g| generate_feature(g, rv) }
|
212
|
-
elsif type == Feature::MultiPolygon
|
213
|
-
emit_integer(obj.num_geometries, rv)
|
214
|
-
obj.each { |g| generate_feature(g, rv) }
|
207
|
+
elsif type_is_collection
|
208
|
+
emit_integer(obj.num_geometries, rval)
|
209
|
+
obj.each { |g| generate_feature(g, rval) }
|
215
210
|
end
|
216
211
|
end
|
217
212
|
end
|