rgeo 2.4.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.
- checksums.yaml +4 -4
- data/.yardopts +6 -0
- data/README.md +1 -0
- data/ext/geos_c_impl/analysis.c +4 -4
- data/ext/geos_c_impl/errors.c +8 -6
- data/ext/geos_c_impl/errors.h +7 -3
- data/ext/geos_c_impl/extconf.rb +2 -0
- data/ext/geos_c_impl/factory.c +80 -7
- data/ext/geos_c_impl/factory.h +28 -14
- data/ext/geos_c_impl/geometry.c +46 -14
- data/ext/geos_c_impl/geometry.h +7 -0
- data/ext/geos_c_impl/geometry_collection.c +2 -104
- data/ext/geos_c_impl/geometry_collection.h +0 -11
- data/ext/geos_c_impl/line_string.c +1 -1
- data/ext/geos_c_impl/point.c +1 -1
- data/ext/geos_c_impl/polygon.c +1 -37
- data/ext/geos_c_impl/preface.h +3 -0
- data/lib/rgeo/cartesian/calculations.rb +54 -17
- data/lib/rgeo/cartesian/factory.rb +0 -7
- data/lib/rgeo/cartesian/feature_classes.rb +66 -46
- data/lib/rgeo/cartesian/feature_methods.rb +51 -20
- data/lib/rgeo/cartesian/interface.rb +0 -6
- data/lib/rgeo/cartesian/planar_graph.rb +379 -0
- data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
- data/lib/rgeo/cartesian/valid_op.rb +71 -0
- data/lib/rgeo/cartesian.rb +3 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
- data/lib/rgeo/error.rb +15 -0
- data/lib/rgeo/feature/geometry.rb +28 -28
- data/lib/rgeo/feature/geometry_collection.rb +13 -5
- data/lib/rgeo/feature/line_string.rb +3 -3
- data/lib/rgeo/feature/multi_surface.rb +3 -3
- data/lib/rgeo/feature/point.rb +4 -4
- data/lib/rgeo/feature/surface.rb +3 -3
- data/lib/rgeo/geographic/factory.rb +0 -7
- data/lib/rgeo/geographic/interface.rb +5 -20
- data/lib/rgeo/geographic/proj4_projector.rb +0 -2
- data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
- data/lib/rgeo/geographic/projected_feature_methods.rb +51 -28
- data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
- data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
- data/lib/rgeo/geographic/spherical_feature_methods.rb +62 -1
- data/lib/rgeo/geos/capi_factory.rb +21 -31
- data/lib/rgeo/geos/capi_feature_classes.rb +35 -11
- data/lib/rgeo/geos/ffi_factory.rb +0 -28
- data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
- data/lib/rgeo/geos/ffi_feature_methods.rb +23 -5
- data/lib/rgeo/geos/interface.rb +0 -7
- data/lib/rgeo/geos/zm_factory.rb +0 -12
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +15 -19
- data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +1 -1
- data/lib/rgeo/impl_helper/valid_op.rb +354 -0
- data/lib/rgeo/impl_helper/validity_check.rb +138 -0
- data/lib/rgeo/impl_helper.rb +1 -0
- data/lib/rgeo/version.rb +1 -1
- metadata +31 -10
@@ -69,41 +69,78 @@ module RGeo
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def intersects_segment?(seg)
|
72
|
+
!segment_intersection(seg).nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
# If this and the other segment intersect, this method will return the coordinate
|
76
|
+
# at which they intersect, otherwise nil.
|
77
|
+
# In the case of a partial overlap (parallel segments), this will return
|
78
|
+
# a single point on the overlapping portion.
|
79
|
+
#
|
80
|
+
# @param seg [Segment]
|
81
|
+
#
|
82
|
+
# @return [RGeo::Feature::Point, nil]
|
83
|
+
def segment_intersection(seg)
|
72
84
|
s2 = seg.s
|
73
85
|
# Handle degenerate cases
|
74
86
|
if seg.degenerate?
|
75
|
-
if @lensq == 0
|
76
|
-
return @s
|
87
|
+
if @lensq == 0 && @s == s2
|
88
|
+
return @s
|
77
89
|
else
|
78
|
-
return contains_point?(s2)
|
90
|
+
return contains_point?(s2) ? s2 : nil
|
79
91
|
end
|
80
92
|
elsif @lensq == 0
|
81
|
-
return seg.contains_point?(@s)
|
93
|
+
return seg.contains_point?(@s) ? @s : nil
|
82
94
|
end
|
95
|
+
|
83
96
|
# Both segments have nonzero length.
|
84
97
|
sx2 = s2.x
|
85
98
|
sy2 = s2.y
|
86
99
|
dx2 = seg.dx
|
87
100
|
dy2 = seg.dy
|
88
101
|
denom = @dx * dy2 - @dy * dx2
|
102
|
+
|
89
103
|
if denom == 0
|
90
104
|
# Segments are parallel. Make sure they are collinear.
|
91
|
-
return
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
105
|
+
return nil unless side(s2) == 0
|
106
|
+
|
107
|
+
# return the first point it finds that intersects another line.
|
108
|
+
# In many cases, the intersection is actually another line
|
109
|
+
# segment, but for now, we will just return a single point.
|
110
|
+
return s2 if contains_point?(s2)
|
111
|
+
return seg.e if contains_point?(seg.e)
|
112
|
+
return @s if seg.contains_point?(@s)
|
113
|
+
return @e if seg.contains_point?(@e)
|
114
|
+
nil
|
100
115
|
else
|
101
116
|
# Segments are not parallel. Check the intersection of their
|
102
117
|
# containing lines.
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
118
|
+
num1 = dx2 * (@sy - sy2) - (dy2 * (@sx - sx2))
|
119
|
+
num2 = @dx * (@sy - sy2) - (@dy * (@sx - sx2))
|
120
|
+
cross1 = num1 / denom
|
121
|
+
cross2 = num2 / denom
|
122
|
+
|
123
|
+
return nil if cross1 < 0.0 || cross1 > 1.0
|
124
|
+
if cross2 >= 0.0 && cross2 <= 1.0
|
125
|
+
x = @sx + (cross1 * @dx)
|
126
|
+
y = @sy + (cross1 * @dy)
|
127
|
+
|
128
|
+
# Check if this segment contains the point.
|
129
|
+
# Sometimes round-off errors occur and intersections
|
130
|
+
# are recorded as off the line segments.
|
131
|
+
#
|
132
|
+
# If this is the case, return the closest point from
|
133
|
+
# either segment.
|
134
|
+
int_pt = @s.factory.point(x, y)
|
135
|
+
if contains_point?(int_pt)
|
136
|
+
int_pt
|
137
|
+
else
|
138
|
+
# find closest of @s, @e, seg.s, seg.e
|
139
|
+
[@e, seg.s, seg.e].reduce(@s) do |closest, pt|
|
140
|
+
int_pt.distance(pt) < int_pt.distance(closest) ? pt : closest
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
107
144
|
end
|
108
145
|
end
|
109
146
|
|
@@ -42,7 +42,6 @@ module RGeo
|
|
42
42
|
end
|
43
43
|
srid ||= @coord_sys.authority_code if @coord_sys
|
44
44
|
@srid = srid.to_i
|
45
|
-
@lenient_assertions = opts[:uses_lenient_assertions] ? true : false
|
46
45
|
@buffer_resolution = opts[:buffer_resolution].to_i
|
47
46
|
@buffer_resolution = 1 if @buffer_resolution < 1
|
48
47
|
|
@@ -103,7 +102,6 @@ module RGeo
|
|
103
102
|
"wkbg" => @wkb_generator.properties,
|
104
103
|
"wktp" => @wkt_parser.properties,
|
105
104
|
"wkbp" => @wkb_parser.properties,
|
106
|
-
"lena" => @lenient_assertions,
|
107
105
|
"bufr" => @buffer_resolution
|
108
106
|
}
|
109
107
|
hash_["proj4"] = @proj4.marshal_dump if @proj4
|
@@ -131,7 +129,6 @@ module RGeo
|
|
131
129
|
wkb_generator: symbolize_hash(data["wkbg"]),
|
132
130
|
wkt_parser: symbolize_hash(data["wktp"]),
|
133
131
|
wkb_parser: symbolize_hash(data["wkbp"]),
|
134
|
-
uses_lenient_assertions: data["lena"],
|
135
132
|
buffer_resolution: data["bufr"],
|
136
133
|
proj4: proj4,
|
137
134
|
coord_sys: coord_sys
|
@@ -144,7 +141,6 @@ module RGeo
|
|
144
141
|
coder["has_z_coordinate"] = @has_z
|
145
142
|
coder["has_m_coordinate"] = @has_m
|
146
143
|
coder["srid"] = @srid
|
147
|
-
coder["lenient_assertions"] = @lenient_assertions
|
148
144
|
coder["buffer_resolution"] = @buffer_resolution
|
149
145
|
coder["wkt_generator"] = @wkt_generator.properties
|
150
146
|
coder["wkb_generator"] = @wkb_generator.properties
|
@@ -180,7 +176,6 @@ module RGeo
|
|
180
176
|
wkb_generator: symbolize_hash(coder["wkb_generator"]),
|
181
177
|
wkt_parser: symbolize_hash(coder["wkt_parser"]),
|
182
178
|
wkb_parser: symbolize_hash(coder["wkb_parser"]),
|
183
|
-
uses_lenient_assertions: coder["lenient_assertions"],
|
184
179
|
buffer_resolution: coder["buffer_resolution"],
|
185
180
|
proj4: proj4,
|
186
181
|
coord_sys: coord_sys
|
@@ -199,8 +194,6 @@ module RGeo
|
|
199
194
|
@has_z
|
200
195
|
when :has_m_coordinate
|
201
196
|
@has_m
|
202
|
-
when :uses_lenient_assertions
|
203
|
-
@lenient_assertions
|
204
197
|
when :buffer_resolution
|
205
198
|
@buffer_resolution
|
206
199
|
when :is_cartesian
|
@@ -9,76 +9,96 @@
|
|
9
9
|
module RGeo
|
10
10
|
module Cartesian
|
11
11
|
class PointImpl # :nodoc:
|
12
|
-
include
|
13
|
-
include
|
14
|
-
include
|
15
|
-
include
|
16
|
-
include
|
12
|
+
include Feature::Point
|
13
|
+
include ImplHelper::ValidityCheck
|
14
|
+
include ImplHelper::BasicGeometryMethods
|
15
|
+
include ImplHelper::BasicPointMethods
|
16
|
+
include ImplHelper::ValidOp
|
17
|
+
include GeometryMethods
|
18
|
+
include PointMethods
|
17
19
|
end
|
18
20
|
|
19
21
|
class LineStringImpl # :nodoc:
|
20
|
-
include
|
21
|
-
include
|
22
|
-
include
|
23
|
-
include
|
24
|
-
include
|
22
|
+
include Feature::LineString
|
23
|
+
include ImplHelper::ValidityCheck
|
24
|
+
include ImplHelper::BasicGeometryMethods
|
25
|
+
include ImplHelper::BasicLineStringMethods
|
26
|
+
include ImplHelper::ValidOp
|
27
|
+
include GeometryMethods
|
28
|
+
include LineStringMethods
|
25
29
|
end
|
26
30
|
|
27
31
|
class LineImpl # :nodoc:
|
28
|
-
include
|
29
|
-
include
|
30
|
-
include
|
31
|
-
include
|
32
|
-
include
|
33
|
-
include
|
32
|
+
include Feature::Line
|
33
|
+
include ImplHelper::ValidityCheck
|
34
|
+
include ImplHelper::BasicGeometryMethods
|
35
|
+
include ImplHelper::BasicLineStringMethods
|
36
|
+
include ImplHelper::BasicLineMethods
|
37
|
+
include ImplHelper::ValidOp
|
38
|
+
include GeometryMethods
|
39
|
+
include LineStringMethods
|
34
40
|
end
|
35
41
|
|
36
42
|
class LinearRingImpl # :nodoc:
|
37
|
-
include
|
38
|
-
include
|
39
|
-
include
|
40
|
-
include
|
41
|
-
include
|
42
|
-
include
|
43
|
+
include Feature::LinearRing
|
44
|
+
include ImplHelper::ValidityCheck
|
45
|
+
include ImplHelper::BasicGeometryMethods
|
46
|
+
include ImplHelper::BasicLineStringMethods
|
47
|
+
include ImplHelper::BasicLinearRingMethods
|
48
|
+
include ImplHelper::ValidOp
|
49
|
+
include GeometryMethods
|
50
|
+
include LineStringMethods
|
43
51
|
end
|
44
52
|
|
45
53
|
class PolygonImpl # :nodoc:
|
46
|
-
include
|
47
|
-
include
|
48
|
-
include
|
49
|
-
include
|
54
|
+
include Feature::Polygon
|
55
|
+
include ImplHelper::ValidityCheck
|
56
|
+
include ImplHelper::BasicGeometryMethods
|
57
|
+
include ImplHelper::BasicPolygonMethods
|
58
|
+
include ValidOp
|
59
|
+
include GeometryMethods
|
50
60
|
end
|
51
61
|
|
52
62
|
class GeometryCollectionImpl # :nodoc:
|
53
|
-
include
|
54
|
-
include
|
55
|
-
include
|
56
|
-
include
|
63
|
+
include Feature::GeometryCollection
|
64
|
+
include ImplHelper::ValidityCheck
|
65
|
+
include ImplHelper::BasicGeometryMethods
|
66
|
+
include ImplHelper::BasicGeometryCollectionMethods
|
67
|
+
include ImplHelper::ValidOp
|
68
|
+
include GeometryMethods
|
57
69
|
end
|
58
70
|
|
59
71
|
class MultiPointImpl # :nodoc:
|
60
|
-
include
|
61
|
-
include
|
62
|
-
include
|
63
|
-
include
|
64
|
-
include
|
72
|
+
include Feature::MultiPoint
|
73
|
+
include ImplHelper::ValidityCheck
|
74
|
+
include ImplHelper::BasicGeometryMethods
|
75
|
+
include ImplHelper::BasicGeometryCollectionMethods
|
76
|
+
include ImplHelper::BasicMultiPointMethods
|
77
|
+
include ImplHelper::ValidOp
|
78
|
+
include GeometryMethods
|
65
79
|
end
|
66
80
|
|
67
81
|
class MultiLineStringImpl # :nodoc:
|
68
|
-
include
|
69
|
-
include
|
70
|
-
include
|
71
|
-
include
|
72
|
-
include
|
73
|
-
include
|
82
|
+
include Feature::MultiLineString
|
83
|
+
include ImplHelper::ValidityCheck
|
84
|
+
include ImplHelper::BasicGeometryMethods
|
85
|
+
include ImplHelper::BasicGeometryCollectionMethods
|
86
|
+
include ImplHelper::BasicMultiLineStringMethods
|
87
|
+
include ImplHelper::ValidOp
|
88
|
+
include GeometryMethods
|
89
|
+
include MultiLineStringMethods
|
74
90
|
end
|
75
91
|
|
76
92
|
class MultiPolygonImpl # :nodoc:
|
77
|
-
include
|
78
|
-
include
|
79
|
-
include
|
80
|
-
include
|
81
|
-
include
|
93
|
+
include Feature::MultiPolygon
|
94
|
+
include ImplHelper::ValidityCheck
|
95
|
+
include ImplHelper::BasicGeometryMethods
|
96
|
+
include ImplHelper::BasicGeometryCollectionMethods
|
97
|
+
include ImplHelper::BasicMultiPolygonMethods
|
98
|
+
include ImplHelper::ValidOp
|
99
|
+
include GeometryMethods
|
82
100
|
end
|
101
|
+
|
102
|
+
ImplHelper::ValidityCheck.override_classes
|
83
103
|
end
|
84
104
|
end
|
@@ -16,6 +16,12 @@ module RGeo
|
|
16
16
|
def envelope
|
17
17
|
BoundingBox.new(factory).add(self).to_geometry
|
18
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def graph
|
23
|
+
@graph ||= GeometryGraph.new(self)
|
24
|
+
end
|
19
25
|
end
|
20
26
|
|
21
27
|
module PointMethods # :nodoc:
|
@@ -50,26 +56,14 @@ module RGeo
|
|
50
56
|
end
|
51
57
|
|
52
58
|
def simple?
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
pindex = index - 1
|
62
|
-
pindex = nil if pindex < 0
|
63
|
-
return false if pindex && seg.contains_point?(segments[pindex].s)
|
64
|
-
next unless nindex
|
65
|
-
oindex = nindex + 1
|
66
|
-
while oindex < len
|
67
|
-
oseg = segments[oindex]
|
68
|
-
return false if !(index == 0 && oindex == len - 1 && seg.s == oseg.e) && seg.intersects_segment?(oseg)
|
69
|
-
oindex += 1
|
70
|
-
end
|
71
|
-
end
|
72
|
-
true
|
59
|
+
# Use a SweeplineIntersector to determine if there are any self-intersections
|
60
|
+
# in the ring. The GeometryGraph of the ring could be used by comparing the
|
61
|
+
# edges to number of segments (graph.incident_edges.length == segments.length),
|
62
|
+
# but this adds computational and memory overhead if graph isn't already memoized.
|
63
|
+
# Since graph is not used elsewhere in LineStringMethods, we will just use the
|
64
|
+
# SweeplineIntersector for now.
|
65
|
+
li = SweeplineIntersector.new(segments)
|
66
|
+
li.proper_intersections.empty?
|
73
67
|
end
|
74
68
|
|
75
69
|
def is_simple?
|
@@ -80,6 +74,43 @@ module RGeo
|
|
80
74
|
def length
|
81
75
|
segments.inject(0.0) { |sum, seg| sum + seg.length }
|
82
76
|
end
|
77
|
+
|
78
|
+
def crosses?(rhs)
|
79
|
+
case rhs
|
80
|
+
when Feature::LineString
|
81
|
+
crosses_line_string?(rhs)
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# Determines if a cross occurs with another linestring.
|
90
|
+
# Process is to get the number of proper intersections in each geom
|
91
|
+
# then overlay and get the number of proper intersections from that.
|
92
|
+
# If the overlaid number is higher than the sum of individual self-ints
|
93
|
+
# then there is an intersection. Finally, we need to check the intersection
|
94
|
+
# to see that it is not a boundary point of either segment.
|
95
|
+
#
|
96
|
+
# @param rhs [Feature::LineString]
|
97
|
+
#
|
98
|
+
# @return [Boolean]
|
99
|
+
def crosses_line_string?(rhs)
|
100
|
+
self_ints = SweeplineIntersector.new(segments).proper_intersections
|
101
|
+
self_ints += SweeplineIntersector.new(rhs.segments).proper_intersections
|
102
|
+
overlay_ints = SweeplineIntersector.new(segments + rhs.segments).proper_intersections
|
103
|
+
|
104
|
+
(overlay_ints - self_ints).each do |int|
|
105
|
+
s1s = int.s1.s
|
106
|
+
s1e = int.s1.e
|
107
|
+
s2s = int.s2.s
|
108
|
+
s2e = int.s2.e
|
109
|
+
return true unless [s1s, s1e, s2s, s2e].include?(int.point)
|
110
|
+
end
|
111
|
+
|
112
|
+
false
|
113
|
+
end
|
83
114
|
end
|
84
115
|
|
85
116
|
module MultiLineStringMethods # :nodoc:
|
@@ -78,12 +78,6 @@ module RGeo
|
|
78
78
|
# Support a Z coordinate. Default is false.
|
79
79
|
# [<tt>:has_m_coordinate</tt>]
|
80
80
|
# Support an M coordinate. Default is false.
|
81
|
-
# [<tt>:uses_lenient_assertions</tt>]
|
82
|
-
# If set to true, assertion checking is disabled. This includes
|
83
|
-
# simplicity checking on LinearRing, and validity checks on
|
84
|
-
# Polygon and MultiPolygon. This may speed up creation of certain
|
85
|
-
# objects, at the expense of not doing the proper checking for
|
86
|
-
# OGC compliance. Default is false.
|
87
81
|
# [<tt>:wkt_parser</tt>]
|
88
82
|
# Configure the parser for WKT. The value is a hash of
|
89
83
|
# configuration parameters for WKRep::WKTParser.new. Default is
|