georuby-ext 0.0.1 → 0.0.2

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