georuby-ext 0.0.1 → 0.0.2

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 (51) hide show
  1. data/.jrubyrc +1 -0
  2. data/.travis.yml +23 -0
  3. data/Gemfile +6 -0
  4. data/Guardfile +12 -2
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +2 -28
  7. data/georuby-ext.gemspec +14 -11
  8. data/lib/georuby-ext.rb +17 -2
  9. data/lib/georuby-ext/core_ext.rb +11 -0
  10. data/lib/georuby-ext/geokit.rb +10 -3
  11. data/lib/georuby-ext/georuby/envelope.rb +36 -1
  12. data/lib/georuby-ext/georuby/ewkb_parser.rb +11 -0
  13. data/lib/georuby-ext/georuby/ewkt_parser.rb +11 -0
  14. data/lib/georuby-ext/georuby/geometry.rb +46 -2
  15. data/lib/georuby-ext/georuby/line_string.rb +19 -7
  16. data/lib/georuby-ext/georuby/linear_ring.rb +15 -0
  17. data/lib/georuby-ext/georuby/locators.rb +30 -17
  18. data/lib/georuby-ext/georuby/multi_polygon.rb +15 -1
  19. data/lib/georuby-ext/georuby/point.rb +148 -24
  20. data/lib/georuby-ext/georuby/polygon.rb +38 -27
  21. data/lib/georuby-ext/georuby/rtree.rb +133 -0
  22. data/lib/georuby-ext/georuby/srid.rb +17 -0
  23. data/lib/georuby-ext/proj4.rb +15 -2
  24. data/lib/georuby-ext/rgeo/cartesian/feature_methods.rb +58 -0
  25. data/lib/georuby-ext/rgeo/feature/geometry.rb +11 -0
  26. data/lib/georuby-ext/rgeo/feature/geometry_collection.rb +11 -0
  27. data/lib/georuby-ext/rgeo/feature/rgeo.rb +157 -0
  28. data/lib/georuby-ext/rgeo/geos/ffi_feature_methods.rb +265 -0
  29. data/lib/georuby-ext/rspec_helper.rb +47 -8
  30. data/spec/lib/geokit_spec.rb +44 -0
  31. data/spec/lib/georuby/envelope_spec.rb +46 -0
  32. data/spec/lib/georuby/geometry_spec.rb +81 -0
  33. data/spec/{georuby → lib/georuby}/line_string_spec.rb +29 -14
  34. data/spec/lib/georuby/linear_ring_spec.rb +52 -0
  35. data/spec/lib/georuby/locators_spec.rb +123 -0
  36. data/spec/lib/georuby/multi_polygon_spec.rb +69 -0
  37. data/spec/lib/georuby/point_spec.rb +248 -0
  38. data/spec/lib/georuby/polygon_spec.rb +175 -0
  39. data/spec/lib/georuby/rtree_spec.rb +132 -0
  40. data/spec/lib/proj4_spec.rb +24 -0
  41. data/spec/lib/rgeo/cartesian/feature_methods_spec.rb +110 -0
  42. data/spec/lib/rgeo/geos/ffi_feature_methods_spec.rb +234 -0
  43. data/spec/spec_helper.rb +12 -8
  44. metadata +224 -189
  45. data/lib/georuby-ext/rgeo.rb +0 -23
  46. data/spec/georuby/linear_ring_spec.rb +0 -33
  47. data/spec/georuby/locators_spec.rb +0 -120
  48. data/spec/georuby/multi_polygon_spec.rb +0 -29
  49. data/spec/georuby/point_spec.rb +0 -44
  50. data/spec/georuby/polygon_spec.rb +0 -134
  51. data/spec/rgeo_spec.rb +0 -81
@@ -0,0 +1,17 @@
1
+ class GeoRuby::SimpleFeatures::Srid
2
+ attr_accessor :srid
3
+
4
+ def initialize(srid)
5
+ @srid ||= srid
6
+ end
7
+
8
+ @@instances = {}
9
+ def self.new(srid)
10
+ @@instances[srid] ||= super(srid)
11
+ end
12
+
13
+ def rgeo_factory
14
+ @rgeo_factory ||= RGeo::Geos.factory(:srid => srid, :wkt_parser => {:support_ewkt => true})
15
+ end
16
+
17
+ end
@@ -1,11 +1,24 @@
1
1
  class Proj4::Projection
2
2
 
3
+ @@wgs84 = nil
3
4
  def self.wgs84
4
- Proj4::Projection.new '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
5
+ @@wgs84 ||= Proj4::Projection.new '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
5
6
  end
6
7
 
8
+ @@goggle = nil
7
9
  def self.google
8
- Proj4::Projection.new '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs'
10
+ @@google ||= Proj4::Projection.new '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs'
11
+ end
12
+
13
+ def self.for_srid(srid)
14
+ case srid
15
+ when 4326
16
+ wgs84
17
+ when 900913
18
+ google
19
+ else
20
+ raise "Unsupported srid: #{srid}"
21
+ end
9
22
  end
10
23
 
11
24
  end
@@ -0,0 +1,58 @@
1
+ module RGeo
2
+ module Cartesian
3
+ module GeometryMethods
4
+
5
+ def to_georuby
6
+ if self.class == PointImpl
7
+ GeoRuby::SimpleFeatures::Point.from_x_y x, y, srid
8
+ elsif self.class == LineStringImpl
9
+ GeoRuby::SimpleFeatures::LineString.from_points points.collect(&:to_georuby), srid
10
+ elsif self.class == LinearRingImpl
11
+ GeoRuby::SimpleFeatures::LinearRing.from_points points.collect(&:to_georuby), srid
12
+ elsif self.class == PolygonImpl
13
+ GeoRuby::SimpleFeatures::Polygon.from_linear_rings linear_rings.collect(&:to_georuby), srid
14
+ else
15
+ GeoRuby::SimpleFeatures::Geometry.from_geometry collect(&:to_georuby), srid
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
22
+ module GeometryCollectionMethods
23
+ def to_georuby
24
+ if self.class == MultiPolygonImpl
25
+ GeoRuby::SimpleFeatures::MultiPolygon.from_polygons collect(&:to_georuby), srid
26
+ else
27
+ GeoRuby::SimpleFeatures::GeometryCollection.from_geometries collect(&:to_georuby), srid
28
+ end
29
+ end
30
+ end
31
+
32
+ module LineStringMethods
33
+ def to_linear_ring
34
+ linear_ring_points = points.first == points.last ? points : points.push(points.first)
35
+ factory.linear_ring linear_ring_points
36
+ end
37
+ end
38
+
39
+ module LinearRingMethods
40
+ def to_linear_ring
41
+ linear_ring_points = points.first == points.last ? points : points.push(points.first)
42
+ factory.linear_ring linear_ring_points
43
+ end
44
+ end
45
+
46
+ module PolygonMethods
47
+ def rings
48
+ [exterior_ring] + interior_rings
49
+ end
50
+
51
+ def linear_rings
52
+ rings.collect(&:to_linear_ring)
53
+ end
54
+ end
55
+
56
+
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ module RGeo
2
+ module Feature
3
+ module Geometry
4
+
5
+ def to_georuby
6
+ raise Error::UnsupportedOperation, "Method Geometry#to_georuby not defined."
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module RGeo
2
+ module Feature
3
+ module GeometryCollection
4
+
5
+ def to_georuby
6
+ raise Error::UnsupportedOperation, "Method GeometryCollection#to_georuby not defined."
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,157 @@
1
+ # module RGeo
2
+
3
+ # module Feature
4
+
5
+ # module Point
6
+ # def to_georuby
7
+ # GeoRuby::SimpleFeatures::Point.from_x_y x, y, srid
8
+ # end
9
+ # end
10
+
11
+ # module LineString
12
+ # def to_georuby
13
+ # GeoRuby::SimpleFeatures::LineString.from_points points.collect(&:to_georuby), srid
14
+ # end
15
+
16
+ # def to_linear_ring
17
+ # linear_ring_points = points.first == points.last ? points : points.push(points.first)
18
+ # factory.linear_ring linear_ring_points
19
+ # end
20
+ # end
21
+
22
+ # module LinearRing
23
+ # def to_georuby
24
+ # GeoRuby::SimpleFeatures::LinearRing.from_points points.collect(&:to_georuby), srid
25
+ # end
26
+
27
+ # def to_linear_ring
28
+ # linear_ring_points = points.first == points.last ? points : points.push(points.first)
29
+ # factory.linear_ring linear_ring_points
30
+ # end
31
+ # end
32
+
33
+ # module Polygon
34
+ # def rings
35
+ # [exterior_ring] + interior_rings
36
+ # end
37
+
38
+ # def linear_rings
39
+ # rings.collect(&:to_linear_ring)
40
+ # end
41
+
42
+ # def to_georuby
43
+ # GeoRuby::SimpleFeatures::Polygon.from_linear_rings linear_rings.collect(&:to_georuby), srid
44
+ # end
45
+ # end
46
+
47
+ # module MultiPolygon
48
+ # def to_georuby
49
+ # GeoRuby::SimpleFeatures::MultiPolygon.from_polygons collect(&:to_georuby), srid
50
+ # end
51
+ # end
52
+
53
+ # module GeometryCollection
54
+ # def to_georuby
55
+ # GeoRuby::SimpleFeatures::GeometryCollection.from_geometries collect(&:to_georuby), srid
56
+ # end
57
+ # end
58
+
59
+ # end
60
+ # end
61
+
62
+ # ###############################
63
+ # # FFI #
64
+ # ###############################
65
+ # class RGeo::Geos::FFIPointImpl
66
+ # def to_georuby
67
+ # GeoRuby::SimpleFeatures::Point.from_x_y x, y, srid
68
+ # end
69
+ # end
70
+
71
+ # class RGeo::Geos::FFILineStringImpl
72
+ # def to_georuby
73
+ # GeoRuby::SimpleFeatures::LineString.from_points points.collect(&:to_georuby), srid
74
+ # end
75
+
76
+ # def to_linear_ring
77
+ # linear_ring_points = points.first == points.last ? points : points.push(points.first)
78
+ # factory.linear_ring linear_ring_points
79
+ # end
80
+ # end
81
+
82
+ # class RGeo::Geos::FFILinearRingImpl
83
+ # def to_georuby
84
+ # GeoRuby::SimpleFeatures::LinearRing.from_points points.collect(&:to_georuby), srid
85
+ # end
86
+
87
+ # def to_linear_ring
88
+ # linear_ring_points = points.first == points.last ? points : points.push(points.first)
89
+ # factory.linear_ring linear_ring_points
90
+ # end
91
+ # end
92
+
93
+ # class RGeo::Geos::FFIPolygonImpl
94
+ # def rings
95
+ # [exterior_ring] + interior_rings
96
+ # end
97
+
98
+ # def linear_rings
99
+ # rings.collect(&:to_linear_ring)
100
+ # end
101
+
102
+ # def to_georuby
103
+ # GeoRuby::SimpleFeatures::Polygon.from_linear_rings linear_rings.collect(&:to_georuby), srid
104
+ # end
105
+ # end
106
+
107
+ # class RGeo::Geos::FFIMultiPolygonImpl
108
+ # def to_georuby
109
+ # GeoRuby::SimpleFeatures::MultiPolygon.from_polygons collect(&:to_georuby), srid
110
+ # end
111
+ # end
112
+
113
+ # class RGeo::Geos::FFIGeometryCollectionImpl
114
+ # def to_georuby
115
+ # GeoRuby::SimpleFeatures::GeometryCollection.from_geometries collect(&:to_georuby), srid
116
+ # end
117
+ # end
118
+
119
+
120
+ # ###############################
121
+ # # CAPI #
122
+ # ###############################
123
+ # class RGeo::Geos::CAPIPointImpl
124
+ # def to_georuby
125
+ # GeoRuby::SimpleFeatures::Point.from_x_y x, y, srid
126
+ # end
127
+ # end
128
+
129
+ # class RGeo::Geos::CAPILineStringImpl
130
+ # def to_georuby
131
+ # GeoRuby::SimpleFeatures::LineString.from_points points.collect(&:to_georuby), srid
132
+ # end
133
+ # end
134
+
135
+ # class RGeo::Geos::CAPILinearRingImpl
136
+ # def to_georuby
137
+ # GeoRuby::SimpleFeatures::LinearRing.from_points points.collect(&:to_georuby), srid
138
+ # end
139
+ # end
140
+
141
+ # class RGeo::Geos::CAPIPolygonImpl
142
+ # def to_georuby
143
+ # GeoRuby::SimpleFeatures::Polygon.from_linear_rings [exterior_ring.to_georuby] + interior_rings.map(&:to_georuby), srid
144
+ # end
145
+ # end
146
+
147
+ # class RGeo::Geos::CAPIMultiPolygonImpl
148
+ # def to_georuby
149
+ # GeoRuby::SimpleFeatures::MultiPolygon.from_polygons collect(&:to_georuby), srid
150
+ # end
151
+ # end
152
+
153
+ # class RGeo::Geos::CAPIGeometryCollectionImpl
154
+ # def to_georuby
155
+ # GeoRuby::SimpleFeatures::GeometryCollection.from_geometries collect(&:to_georuby), srid
156
+ # end
157
+ # end
@@ -0,0 +1,265 @@
1
+ module RGeo
2
+ module Geos
3
+ module FFIGeometryMethods
4
+
5
+ def to_georuby
6
+ if self.class == FFIPointImpl
7
+ GeoRuby::SimpleFeatures::Point.from_x_y x, y, srid
8
+ elsif self.class == FFILineStringImpl
9
+ GeoRuby::SimpleFeatures::LineString.from_points points.collect(&:to_georuby), srid
10
+ elsif self.class == FFILinearRingImpl
11
+ GeoRuby::SimpleFeatures::LinearRing.from_points points.collect(&:to_georuby), srid
12
+ elsif self.class == FFIPolygonImpl
13
+ GeoRuby::SimpleFeatures::Polygon.from_linear_rings linear_rings.collect(&:to_georuby), srid
14
+ else
15
+ GeoRuby::SimpleFeatures::Geometry.from_geometry collect(&:to_georuby), srid
16
+ end
17
+
18
+ end
19
+
20
+ def to_geometry
21
+ self
22
+ end
23
+
24
+ end
25
+
26
+ module FFIGeometryCollectionMethods
27
+ alias_method :geometries, :each
28
+
29
+ def to_georuby
30
+ if self.class == FFIMultiPolygonImpl
31
+ GeoRuby::SimpleFeatures::MultiPolygon.from_polygons collect(&:to_georuby), srid
32
+ else
33
+ GeoRuby::SimpleFeatures::GeometryCollection.from_geometries collect(&:to_georuby), srid
34
+ end
35
+ end
36
+
37
+ def to_geometry
38
+ self
39
+ end
40
+ end
41
+
42
+ module FFILineStringMethods
43
+
44
+ def to_linear_ring
45
+ linear_ring_points = points.first == points.last ? points : points.push(points.first)
46
+ factory.linear_ring linear_ring_points
47
+ end
48
+
49
+ def locate_point(target)
50
+ distance_on_line(target) / length
51
+ end
52
+
53
+ def distance_on_line(target)
54
+ nearest_locator = nearest_locator(target)
55
+ nearest_locator.distance_on_segment + nearest_locator.segment.line_distance_at_departure
56
+ end
57
+
58
+ def distance_from_line(target)
59
+ nearest_locator(target).distance_from_segment
60
+ end
61
+
62
+ def nearest_locator(target)
63
+ locators(target).min_by(&:distance_from_segment)
64
+ end
65
+
66
+ def locators(point)
67
+ segments.collect { |segment| segment.locator(point) }
68
+ end
69
+
70
+ def segments_without_cache
71
+ previous_point = nil
72
+ distance_from_departure = 0
73
+
74
+
75
+ points.inject([]) do |segments, point|
76
+ Segment.new(previous_point, point).tap do |segment|
77
+ segment.line = self
78
+ segment.line_distance_at_departure = distance_from_departure
79
+
80
+ distance_from_departure += segment.distance
81
+
82
+ segments << segment
83
+ end if previous_point
84
+
85
+ previous_point = point
86
+ segments
87
+ end
88
+ end
89
+
90
+ def segments_with_cache
91
+ @segments ||= segments_without_cache
92
+ end
93
+ alias_method :segments, :segments_with_cache
94
+
95
+ def interpolate_point(location)
96
+ return points.last if location >= 1
97
+ return points.first if location <= 0
98
+
99
+ distance_on_line = location * spherical_distance
100
+
101
+ segment = segments.find do |segment|
102
+ segment.line_distance_at_arrival > distance_on_line
103
+ end
104
+
105
+ location_on_segment =
106
+ (distance_on_line - segment.line_distance_at_departure) / segment.distance
107
+
108
+ segment.interpolate_point location_on_segment
109
+ end
110
+
111
+ class Segment
112
+
113
+ attr_reader :departure, :arrival
114
+
115
+ def initialize(departure, arrival)
116
+ @departure, @arrival = departure, arrival
117
+ end
118
+
119
+ attr_accessor :line, :line_distance_at_departure
120
+
121
+ def line_distance_at_arrival
122
+ line_distance_at_departure + distance
123
+ end
124
+
125
+ def locator(target)
126
+ PointLocator.new target, self
127
+ end
128
+
129
+ def location_in_line
130
+ if line and line_distance_at_departure
131
+ line_distance_at_departure / line.length
132
+ end
133
+ end
134
+
135
+ def square_of_distance
136
+ distance**2
137
+ end
138
+
139
+ def distance
140
+ @distance ||= departure.distance(arrival)
141
+ end
142
+
143
+ def to_s
144
+ "#{departure.x},#{departure.y}..#{arrival.x},#{arrival.y}"
145
+ end
146
+
147
+ def interpolate_point(location)
148
+ dx, dy = (arrival.x - departure.x) * location, (arrival.y - departure.y) * location
149
+ RGeo::Geos::FFIPoint.from_x_y departure.x + dx, departure.y + dy, line.srid
150
+ end
151
+
152
+ end
153
+
154
+ class PointLocator
155
+ extend ActiveSupport::Memoizable
156
+ include Math
157
+
158
+ attr_reader :target, :segment, :factory
159
+ delegate :departure, :arrival, :to => :segment
160
+
161
+ def initialize(target, segment_or_departure, arrival = nil)
162
+ @segment =
163
+ if arrival
164
+ Segment.new(segment_or_departure, arrival)
165
+ else
166
+ segment_or_departure
167
+ end
168
+ @target = target
169
+ @factory = departure.factory
170
+ raise "Target is not defined" unless target
171
+ end
172
+
173
+ def distance_on_segment
174
+ Math.sqrt( target_distance_from_departure**2 - target_distance_from_segment**2 )
175
+ end
176
+
177
+ def distance_from_segment
178
+ return 0 if [segment.departure, segment.arrival].include?(target)
179
+ target_distance_from_segment
180
+ end
181
+
182
+ def target_distance_from_departure
183
+ departure.distance target
184
+ end
185
+
186
+ def target_distance_from_segment
187
+ target.distance(factory.line_string([segment.departure, segment.arrival]))
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+
194
+ module FFIMultiLineStringMethods
195
+
196
+ def locate_point(target)
197
+ nearest_locator = nearest_locator(target)
198
+ nearest_locator.location + nearest_locator.index
199
+ end
200
+
201
+ def interpolate_point(location)
202
+ line_index, line_location = location.to_i, location % 1
203
+ if line = geometries[line_index]
204
+ line.interpolate_point(line_location)
205
+ end
206
+ end
207
+
208
+ def nearest_locator(target)
209
+ locators(target).min_by(&:distance_from_line)
210
+ end
211
+
212
+ def locators(point)
213
+ [].tap do |locators|
214
+ geometries.each_with_index do |line, index|
215
+ locators << PointLocator.new(point, line, index)
216
+ end
217
+ end
218
+ end
219
+
220
+ class PointLocator
221
+
222
+ attr_reader :target, :line, :index
223
+
224
+ def initialize(target, line, index)
225
+ @target = target
226
+ @line = line
227
+ @index = index
228
+ end
229
+
230
+ def location
231
+ line.locate_point(target)
232
+ end
233
+
234
+ def distance_on_line
235
+ line.distance_on_line(target)
236
+ end
237
+
238
+ def distance_from_line
239
+ line.distance_from_line(target)
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+
246
+ module FFILinearRingMethods
247
+ def to_linear_ring
248
+ linear_ring_points = points.first == points.last ? points : points.push(points.first)
249
+ factory.linear_ring linear_ring_points
250
+ end
251
+ end
252
+
253
+ module FFIPolygonMethods
254
+ def rings
255
+ [exterior_ring] + interior_rings
256
+ end
257
+
258
+ def linear_rings
259
+ rings.collect(&:to_linear_ring)
260
+ end
261
+ end
262
+
263
+
264
+ end
265
+ end