schleyfox-rgeo 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/History.rdoc +199 -0
  2. data/README.rdoc +172 -0
  3. data/Spatial_Programming_With_RGeo.rdoc +440 -0
  4. data/Version +1 -0
  5. data/ext/geos_c_impl/extconf.rb +84 -0
  6. data/ext/geos_c_impl/factory.c +468 -0
  7. data/ext/geos_c_impl/factory.h +224 -0
  8. data/ext/geos_c_impl/geometry.c +705 -0
  9. data/ext/geos_c_impl/geometry.h +55 -0
  10. data/ext/geos_c_impl/geometry_collection.c +482 -0
  11. data/ext/geos_c_impl/geometry_collection.h +69 -0
  12. data/ext/geos_c_impl/line_string.c +509 -0
  13. data/ext/geos_c_impl/line_string.h +64 -0
  14. data/ext/geos_c_impl/main.c +70 -0
  15. data/ext/geos_c_impl/point.c +193 -0
  16. data/ext/geos_c_impl/point.h +62 -0
  17. data/ext/geos_c_impl/polygon.c +265 -0
  18. data/ext/geos_c_impl/polygon.h +66 -0
  19. data/ext/geos_c_impl/preface.h +50 -0
  20. data/ext/proj4_c_impl/extconf.rb +88 -0
  21. data/ext/proj4_c_impl/main.c +271 -0
  22. data/lib/rgeo.rb +124 -0
  23. data/lib/rgeo/cartesian.rb +60 -0
  24. data/lib/rgeo/cartesian/analysis.rb +118 -0
  25. data/lib/rgeo/cartesian/bounding_box.rb +337 -0
  26. data/lib/rgeo/cartesian/calculations.rb +161 -0
  27. data/lib/rgeo/cartesian/factory.rb +209 -0
  28. data/lib/rgeo/cartesian/feature_classes.rb +173 -0
  29. data/lib/rgeo/cartesian/feature_methods.rb +106 -0
  30. data/lib/rgeo/cartesian/interface.rb +150 -0
  31. data/lib/rgeo/coord_sys.rb +79 -0
  32. data/lib/rgeo/coord_sys/cs/entities.rb +1524 -0
  33. data/lib/rgeo/coord_sys/cs/factories.rb +208 -0
  34. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +308 -0
  35. data/lib/rgeo/coord_sys/proj4.rb +312 -0
  36. data/lib/rgeo/coord_sys/srs_database/active_record_table.rb +194 -0
  37. data/lib/rgeo/coord_sys/srs_database/interface.rb +165 -0
  38. data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +188 -0
  39. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +108 -0
  40. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +108 -0
  41. data/lib/rgeo/error.rb +63 -0
  42. data/lib/rgeo/feature.rb +88 -0
  43. data/lib/rgeo/feature/curve.rb +156 -0
  44. data/lib/rgeo/feature/factory.rb +332 -0
  45. data/lib/rgeo/feature/factory_generator.rb +138 -0
  46. data/lib/rgeo/feature/geometry.rb +614 -0
  47. data/lib/rgeo/feature/geometry_collection.rb +129 -0
  48. data/lib/rgeo/feature/line.rb +66 -0
  49. data/lib/rgeo/feature/line_string.rb +102 -0
  50. data/lib/rgeo/feature/linear_ring.rb +66 -0
  51. data/lib/rgeo/feature/multi_curve.rb +113 -0
  52. data/lib/rgeo/feature/multi_line_string.rb +66 -0
  53. data/lib/rgeo/feature/multi_point.rb +73 -0
  54. data/lib/rgeo/feature/multi_polygon.rb +97 -0
  55. data/lib/rgeo/feature/multi_surface.rb +116 -0
  56. data/lib/rgeo/feature/point.rb +120 -0
  57. data/lib/rgeo/feature/polygon.rb +141 -0
  58. data/lib/rgeo/feature/surface.rb +122 -0
  59. data/lib/rgeo/feature/types.rb +305 -0
  60. data/lib/rgeo/geographic.rb +75 -0
  61. data/lib/rgeo/geographic/factory.rb +287 -0
  62. data/lib/rgeo/geographic/interface.rb +410 -0
  63. data/lib/rgeo/geographic/proj4_projector.rb +98 -0
  64. data/lib/rgeo/geographic/projected_feature_classes.rb +213 -0
  65. data/lib/rgeo/geographic/projected_feature_methods.rb +228 -0
  66. data/lib/rgeo/geographic/projected_window.rb +467 -0
  67. data/lib/rgeo/geographic/simple_mercator_projector.rb +157 -0
  68. data/lib/rgeo/geographic/spherical_feature_classes.rb +212 -0
  69. data/lib/rgeo/geographic/spherical_feature_methods.rb +97 -0
  70. data/lib/rgeo/geographic/spherical_math.rb +206 -0
  71. data/lib/rgeo/geos.rb +72 -0
  72. data/lib/rgeo/geos/factory.rb +301 -0
  73. data/lib/rgeo/geos/impl_additions.rb +76 -0
  74. data/lib/rgeo/geos/interface.rb +139 -0
  75. data/lib/rgeo/geos/zm_factory.rb +275 -0
  76. data/lib/rgeo/geos/zm_impl.rb +432 -0
  77. data/lib/rgeo/impl_helper.rb +53 -0
  78. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +235 -0
  79. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +85 -0
  80. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +197 -0
  81. data/lib/rgeo/impl_helper/basic_point_methods.rb +138 -0
  82. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +121 -0
  83. data/lib/rgeo/impl_helper/math.rb +50 -0
  84. data/lib/rgeo/version.rb +52 -0
  85. data/lib/rgeo/wkrep.rb +72 -0
  86. data/lib/rgeo/wkrep/wkb_generator.rb +267 -0
  87. data/lib/rgeo/wkrep/wkb_parser.rb +315 -0
  88. data/lib/rgeo/wkrep/wkt_generator.rb +275 -0
  89. data/lib/rgeo/wkrep/wkt_parser.rb +496 -0
  90. data/test/common/geometry_collection_tests.rb +238 -0
  91. data/test/common/line_string_tests.rb +324 -0
  92. data/test/common/multi_line_string_tests.rb +209 -0
  93. data/test/common/multi_point_tests.rb +201 -0
  94. data/test/common/multi_polygon_tests.rb +208 -0
  95. data/test/common/point_tests.rb +331 -0
  96. data/test/common/polygon_tests.rb +232 -0
  97. data/test/coord_sys/tc_active_record_table.rb +102 -0
  98. data/test/coord_sys/tc_ogc_cs.rb +356 -0
  99. data/test/coord_sys/tc_proj4.rb +138 -0
  100. data/test/coord_sys/tc_proj4_srs_data.rb +76 -0
  101. data/test/coord_sys/tc_sr_org.rb +70 -0
  102. data/test/coord_sys/tc_url_reader.rb +82 -0
  103. data/test/geos/tc_factory.rb +91 -0
  104. data/test/geos/tc_geometry_collection.rb +62 -0
  105. data/test/geos/tc_line_string.rb +62 -0
  106. data/test/geos/tc_misc.rb +72 -0
  107. data/test/geos/tc_multi_line_string.rb +62 -0
  108. data/test/geos/tc_multi_point.rb +62 -0
  109. data/test/geos/tc_multi_polygon.rb +63 -0
  110. data/test/geos/tc_point.rb +86 -0
  111. data/test/geos/tc_polygon.rb +86 -0
  112. data/test/geos/tc_zmfactory.rb +85 -0
  113. data/test/projected_geographic/tc_geometry_collection.rb +62 -0
  114. data/test/projected_geographic/tc_line_string.rb +62 -0
  115. data/test/projected_geographic/tc_multi_line_string.rb +62 -0
  116. data/test/projected_geographic/tc_multi_point.rb +62 -0
  117. data/test/projected_geographic/tc_multi_polygon.rb +63 -0
  118. data/test/projected_geographic/tc_point.rb +93 -0
  119. data/test/projected_geographic/tc_polygon.rb +62 -0
  120. data/test/simple_cartesian/tc_calculations.rb +145 -0
  121. data/test/simple_cartesian/tc_geometry_collection.rb +69 -0
  122. data/test/simple_cartesian/tc_line_string.rb +70 -0
  123. data/test/simple_cartesian/tc_multi_line_string.rb +67 -0
  124. data/test/simple_cartesian/tc_multi_point.rb +67 -0
  125. data/test/simple_cartesian/tc_multi_polygon.rb +70 -0
  126. data/test/simple_cartesian/tc_point.rb +91 -0
  127. data/test/simple_cartesian/tc_polygon.rb +67 -0
  128. data/test/simple_mercator/tc_geometry_collection.rb +62 -0
  129. data/test/simple_mercator/tc_line_string.rb +62 -0
  130. data/test/simple_mercator/tc_multi_line_string.rb +62 -0
  131. data/test/simple_mercator/tc_multi_point.rb +62 -0
  132. data/test/simple_mercator/tc_multi_polygon.rb +63 -0
  133. data/test/simple_mercator/tc_point.rb +93 -0
  134. data/test/simple_mercator/tc_polygon.rb +62 -0
  135. data/test/simple_mercator/tc_window.rb +219 -0
  136. data/test/spherical_geographic/tc_calculations.rb +203 -0
  137. data/test/spherical_geographic/tc_geometry_collection.rb +70 -0
  138. data/test/spherical_geographic/tc_line_string.rb +70 -0
  139. data/test/spherical_geographic/tc_multi_line_string.rb +67 -0
  140. data/test/spherical_geographic/tc_multi_point.rb +67 -0
  141. data/test/spherical_geographic/tc_multi_polygon.rb +70 -0
  142. data/test/spherical_geographic/tc_point.rb +100 -0
  143. data/test/spherical_geographic/tc_polygon.rb +67 -0
  144. data/test/tc_cartesian_analysis.rb +107 -0
  145. data/test/tc_oneoff.rb +63 -0
  146. data/test/wkrep/tc_wkb_generator.rb +249 -0
  147. data/test/wkrep/tc_wkb_parser.rb +353 -0
  148. data/test/wkrep/tc_wkt_generator.rb +362 -0
  149. data/test/wkrep/tc_wkt_parser.rb +480 -0
  150. metadata +267 -0
@@ -0,0 +1,312 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Proj4 wrapper for RGeo
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module RGeo
38
+
39
+ module CoordSys
40
+
41
+
42
+ # This is a Ruby wrapper around a Proj4 coordinate system.
43
+ # It represents a single geographic coordinate system, which may be
44
+ # a flat projection, a geocentric (3-dimensional) coordinate system,
45
+ # or a geographic (latitude-longitude) coordinate system.
46
+ #
47
+ # Generally, these are used to define the projection for a
48
+ # Feature::Factory. You can then convert between coordinate systems
49
+ # by casting geometries between such factories using the :project
50
+ # option. You may also use this object directly to perform low-level
51
+ # coordinate transformations.
52
+
53
+ class Proj4
54
+
55
+
56
+ def inspect # :nodoc:
57
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{canonical_str.inspect}>"
58
+ end
59
+
60
+
61
+ def to_s # :nodoc:
62
+ canonical_str
63
+ end
64
+
65
+
66
+ def hash # :nodoc:
67
+ canonical_hash.hash
68
+ end
69
+
70
+
71
+ # Returns true if this Proj4 is equivalent to the given Proj4.
72
+ #
73
+ # Note: this tests for equivalence by comparing only the hash
74
+ # definitions of the Proj4 objects, and returning true if those
75
+ # definitions are equivalent. In some cases, this may still return
76
+ # false even if the actual coordinate systems are identical, since
77
+ # there are sometimes multiple ways to express a given coordinate
78
+ # system.
79
+
80
+ def eql?(rhs_)
81
+ rhs_.class == self.class && rhs_.canonical_hash == canonical_hash && rhs_._radians? == _radians?
82
+ end
83
+ alias_method :==, :eql?
84
+
85
+
86
+ # Returns the "canonical" string definition for this coordinate
87
+ # system, as reported by Proj4. This may be slightly different
88
+ # from the definition used to construct this object.
89
+
90
+ def canonical_str
91
+ unless defined?(@canonical_str)
92
+ @canonical_str = _canonical_str
93
+ end
94
+ @canonical_str
95
+ end
96
+
97
+
98
+ # Returns the "canonical" hash definition for this coordinate
99
+ # system, as reported by Proj4. This may be slightly different
100
+ # from the definition used to construct this object.
101
+
102
+ def canonical_hash
103
+ unless defined?(@canonical_hash)
104
+ @canonical_hash = {}
105
+ canonical_str.strip.split(/\s+/).each do |elem_|
106
+ if elem_ =~ /^\+(\w+)(=(\S+))?$/
107
+ @canonical_hash[$1] = $3
108
+ end
109
+ end
110
+ end
111
+ @canonical_hash
112
+ end
113
+
114
+
115
+ # Returns the string definition originally used to construct this
116
+ # object. Returns nil if this object wasn't created by a string
117
+ # definition; i.e. if it was created using get_geographic.
118
+
119
+ def original_str
120
+ _original_str
121
+ end
122
+
123
+
124
+ # Returns true if this Proj4 object is a geographic (lat-long)
125
+ # coordinate system.
126
+
127
+ def geographic?
128
+ _geographic?
129
+ end
130
+
131
+
132
+ # Returns true if this Proj4 object is a geocentric (3dz)
133
+ # coordinate system.
134
+
135
+ def geocentric?
136
+ _geocentric?
137
+ end
138
+
139
+
140
+ # Returns true if this Proj4 object uses radians rather than degrees
141
+ # if it is a geographic coordinate system.
142
+
143
+ def radians?
144
+ _radians?
145
+ end
146
+
147
+
148
+ # Get the geographic (unprojected lat-long) coordinate system
149
+ # corresponding to this coordinate system; i.e. the one that uses
150
+ # the same ellipsoid and datum.
151
+
152
+ def get_geographic
153
+ _get_geographic
154
+ end
155
+
156
+
157
+ class << self
158
+
159
+
160
+ # Returns true if Proj4 is supported in this installation.
161
+ # If this returns false, the other methods such as create
162
+ # will not work.
163
+
164
+ def supported?
165
+ respond_to?(:_create)
166
+ end
167
+
168
+
169
+ # Create a new Proj4 object, given a definition, which may be
170
+ # either a string or a hash. Returns nil if the given definition
171
+ # is invalid or Proj4 is not supported.
172
+ #
173
+ # Recognized options include:
174
+ #
175
+ # [<tt>:radians</tt>]
176
+ # If set to true, then this proj4 will represent geographic
177
+ # (latitude/longitude) coordinates in radians rather than
178
+ # degrees. If this is a geographic coordinate system, then its
179
+ # units will be in radians. If this is a projected coordinate
180
+ # system, then its units will be unchanged, but any geographic
181
+ # coordinate system obtained using get_geographic will use
182
+ # radians as its units. If this is a geocentric or other type of
183
+ # coordinate system, this has no effect. Default is false.
184
+ # (That is all coordinates are in degrees by default.)
185
+
186
+ def create(defn_, opts_={})
187
+ result_ = nil
188
+ if supported?
189
+ if defn_.kind_of?(::Hash)
190
+ defn_ = defn_.map{ |k_, v_| v_ ? "+#{k_}=#{v_}" : "+#{k_}" }.join(' ')
191
+ end
192
+ unless defn_ =~ /^\s*\+/
193
+ defn_ = defn_.sub(/^(\s*)/, '\1+').gsub(/(\s+)([^+\s])/, '\1+\2')
194
+ end
195
+ result_ = _create(defn_, opts_[:radians])
196
+ result_ = nil unless result_._valid?
197
+ end
198
+ result_
199
+ end
200
+
201
+
202
+ # Create a new Proj4 object, given a definition, which may be
203
+ # either a string or a hash. Raises Error::UnsupportedOperation
204
+ # if the given definition is invalid or Proj4 is not supported.
205
+
206
+ def new(defn_, opts_={})
207
+ result_ = create(defn_, opts_)
208
+ unless result_
209
+ raise Error::UnsupportedOperation, "Proj4 not supported in this installation"
210
+ end
211
+ result_
212
+ end
213
+
214
+
215
+ # Low-level coordinate transform method.
216
+ # Transforms the given coordinate (x, y, [z]) from one proj4
217
+ # coordinate system to another. Returns an array with either two
218
+ # or three elements.
219
+
220
+ def transform_coords(from_proj_, to_proj_, x_, y_, z_=nil)
221
+ if !from_proj_._radians? && from_proj_._geographic?
222
+ x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
223
+ y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
224
+ end
225
+ result_ = _transform_coords(from_proj_, to_proj_, x_, y_, z_)
226
+ if result_ && !to_proj_._radians? && to_proj_._geographic?
227
+ result_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
228
+ result_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
229
+ end
230
+ result_
231
+ end
232
+
233
+
234
+ # Low-level geometry transform method.
235
+ # Transforms the given geometry between the given two projections.
236
+ # The resulting geometry is constructed using the to_factory.
237
+ # Any projections associated with the factories themselves are
238
+ # ignored.
239
+
240
+ def transform(from_proj_, from_geometry_, to_proj_, to_factory_)
241
+ case from_geometry_
242
+ when Feature::Point
243
+ _transform_point(from_proj_, from_geometry_, to_proj_, to_factory_)
244
+ when Feature::Line
245
+ to_factory_.line(from_geometry_.points.map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
246
+ when Feature::LinearRing
247
+ _transform_linear_ring(from_proj_, from_geometry_, to_proj_, to_factory_)
248
+ when Feature::LineString
249
+ to_factory_.line_string(from_geometry_.points.map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
250
+ when Feature::Polygon
251
+ _transform_polygon(from_proj_, from_geometry_, to_proj_, to_factory_)
252
+ when Feature::MultiPoint
253
+ to_factory_.multi_point(from_geometry_.map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
254
+ when Feature::MultiLineString
255
+ to_factory_.multi_line_string(from_geometry_.map{ |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
256
+ when Feature::MultiPolygon
257
+ to_factory_.multi_polygon(from_geometry_.map{ |p_| _transform_polygon(from_proj_, p_, to_proj_, to_factory_) })
258
+ when Feature::GeometryCollection
259
+ to_factory_.collection(from_geometry_.map{ |g_| transform(from_proj_, g_, to_proj_, to_factory_) })
260
+ end
261
+ end
262
+
263
+
264
+ def _transform_point(from_proj_, from_point_, to_proj_, to_factory_) # :nodoc:
265
+ from_factory_ = from_point_.factory
266
+ from_has_z_ = from_factory_.property(:has_z_coordinate)
267
+ from_has_m_ = from_factory_.property(:has_m_coordinate)
268
+ to_has_z_ = to_factory_.property(:has_z_coordinate)
269
+ to_has_m_ = to_factory_.property(:has_m_coordinate)
270
+ x_ = from_point_.x
271
+ y_ = from_point_.y
272
+ if !from_proj_._radians? && from_proj_._geographic?
273
+ x_ *= ImplHelper::Math::RADIANS_PER_DEGREE
274
+ y_ *= ImplHelper::Math::RADIANS_PER_DEGREE
275
+ end
276
+ coords_ = _transform_coords(from_proj_, to_proj_, x_, y_, from_has_z_ ? from_point_.z : nil)
277
+ if coords_
278
+ if !to_proj_._radians? && to_proj_._geographic?
279
+ coords_[0] *= ImplHelper::Math::DEGREES_PER_RADIAN
280
+ coords_[1] *= ImplHelper::Math::DEGREES_PER_RADIAN
281
+ end
282
+ extras_ = []
283
+ extras_ << coords_[2].to_f if to_has_z_
284
+ extras_ << from_has_m_ ? from_point_.m : 0.0 if to_has_m_
285
+ to_factory_.point(coords_[0], coords_[1], *extras_)
286
+ else
287
+ nil
288
+ end
289
+ end
290
+
291
+
292
+ def _transform_linear_ring(from_proj_, from_ring_, to_proj_, to_factory_) # :nodoc:
293
+ to_factory_.linear_ring(from_ring_.points[0..-2].map{ |p_| _transform_point(from_proj_, p_, to_proj_, to_factory_) })
294
+ end
295
+
296
+
297
+ def _transform_polygon(from_proj_, from_polygon_, to_proj_, to_factory_) # :nodoc:
298
+ ext_ = _transform_linear_ring(from_proj_, from_polygon_.exterior_ring, to_proj_, to_factory_)
299
+ int_ = from_polygon_.interior_rings.map{ |r_| _transform_linear_ring(from_proj_, r_, to_proj_, to_factory_) }
300
+ to_factory_.polygon(ext_, int_)
301
+ end
302
+
303
+
304
+ end
305
+
306
+
307
+ end
308
+
309
+
310
+ end
311
+
312
+ end
@@ -0,0 +1,194 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # SRS database interface
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module RGeo
38
+
39
+ module CoordSys
40
+
41
+ module SRSDatabase
42
+
43
+
44
+ # A spatial reference database implementation that uses ActiveRecord
45
+ # to access a spatial reference table provided by a spatial database
46
+ # implementation. You can use this class to obtain coordinate system
47
+ # information from your installation of, e.g. PostGIS.
48
+
49
+ class ActiveRecordTable
50
+
51
+ @@class_counter = 0
52
+
53
+
54
+ # Create a new ActiveRecord-backed database connection.
55
+ #
56
+ # Options include:
57
+ #
58
+ # [<tt>:ar_class</tt>]
59
+ # An ActiveRecord class to use. You may provide this if you
60
+ # already have an ActiveRecord class that accesses the table.
61
+ # If not provided, an ActiveRecord class will be generated
62
+ # for you, using the <tt>:ar_base_class</tt>,
63
+ # <tt>:database_config</tt>, and <tt>:table_name</tt> options.
64
+ # [<tt>:ar_base_class</tt>]
65
+ # Specify an ActiveRecord base class to use when generating an
66
+ # ActiveRecord class. Default is ::ActiveRecord::Base. You may
67
+ # want to use this if you have a base class already that
68
+ # specifies an existing database connection and/or other
69
+ # class-scope options.
70
+ # [<tt>:database_config</tt>]
71
+ # If provided, <tt>establish_connection</tt> will be called on
72
+ # the generated ActiveRecord class, with the given value.
73
+ # [<tt>:table_name</tt>]
74
+ # The table name for the new ActiveRecord class. Defaults to
75
+ # the value <tt>spatial_ref_sys</tt>, which is the OGC-specified
76
+ # name for this table.
77
+ # [<tt>:srid_column</tt>]
78
+ # The name of the SRID column. Defaults to "srid", which is the
79
+ # OGC-specified name for this column.
80
+ # [<tt>:auth_name_column</tt>]
81
+ # The name of the authority name column. On an OGC-compliant
82
+ # database, this column should be named "auth_name". However,
83
+ # the default is set to nil; you should set this option
84
+ # explicitly if you want to read the authority name.
85
+ # [<tt>:auth_srid_column</tt>]
86
+ # The name of the authority srid column. On an OGC-compliant
87
+ # database, this column should be named "auth_srid". However,
88
+ # the default is set to nil; you should set this option
89
+ # explicitly if you want to read the authority's srid.
90
+ # [<tt>:name_column</tt>]
91
+ # The name of the coordinate system name column. This column is
92
+ # not part of the OGC spec, but it is included in some spatial
93
+ # database implementations. Default is nil.
94
+ # [<tt>:description_column</tt>]
95
+ # The name of the coordinate system description column. This
96
+ # column is not part of the OGC spec, but may be included in
97
+ # some spatial database implementations. Default is nil.
98
+ # [<tt>:srtext_column</tt>]
99
+ # The name of the spatial reference WKT column. On an
100
+ # OGC-compliant database, this column should be named "srtext".
101
+ # However, not all databases include this column, so the default
102
+ # is set to nil; you should set this option explicitly if you
103
+ # want to read the OGC coordinate system specification.
104
+ # [<tt>:proj4text_column</tt>]
105
+ # The name of the Proj4 format projection spec column. This
106
+ # column is not part of the OGC spec, but may be included in
107
+ # some spatial database implementations. Default is nil.
108
+ # [<tt>:cache</tt>]
109
+ # If set to true, entries are cached when first retrieved, so
110
+ # subsequent requests do not have to make a database round trip.
111
+ # Default is false.
112
+ #
113
+ # Some option settings may be provided by the ActiveRecord
114
+ # connection adapter, if the ActiveRecord class's connection uses
115
+ # an adapter that is RGeo-savvy. The "postgis" and "spatialite"
116
+ # adapters are such adapters. They automatically provide the
117
+ # <tt>:table_name</tt> and all the relevant column settings for
118
+ # the database-provided spatial reference table as defaults.
119
+ # However, you can still override those settings if you want to
120
+ # use a custom table.
121
+
122
+ def initialize(opts_={})
123
+ @cache = opts_[:cache] ? {} : nil
124
+ @ar_class = opts_[:ar_class]
125
+ unless @ar_class
126
+ ar_base_class_ = opts_[:ar_base_class] || ::ActiveRecord::Base
127
+ @ar_class = ::Class.new(ar_base_class_)
128
+ self.class.const_set("Klass#{@@class_counter}", @ar_class)
129
+ @@class_counter += 1
130
+ @ar_class.class_eval do
131
+ establish_connection(opts_[:database_config]) if opts_[:database_config]
132
+ end
133
+ end
134
+ connection_ = @ar_class.connection
135
+ if connection_.respond_to?(:srs_database_columns)
136
+ opts_ = connection_.srs_database_columns.merge(opts_)
137
+ end
138
+ unless opts_[:ar_class]
139
+ @ar_class.class_eval do
140
+ set_table_name(opts_[:table_name] || 'spatial_ref_sys')
141
+ end
142
+ end
143
+ @srid_column = opts_[:srid_column] || 'srid'
144
+ @auth_name_column = opts_[:auth_name_column]
145
+ @auth_srid_column = opts_[:auth_srid_column]
146
+ @name_column = opts_[:name_column]
147
+ @description_column = opts_[:description_column]
148
+ @srtext_column = opts_[:srtext_column]
149
+ @proj4text_column = opts_[:proj4text_column]
150
+ end
151
+
152
+
153
+ # Retrieve an Entry given an integer SRID.
154
+
155
+ def get(ident_)
156
+ ident_ = ident_.to_i
157
+ return @cache[ident_] if @cache && @cache.include?(ident_)
158
+ obj_ = @ar_class.where(@srid_column => ident_).first
159
+ unless obj_
160
+ @cache[ident_] = nil if @cache
161
+ return nil
162
+ end
163
+ auth_name_ = @auth_name_column ? obj_[@auth_name_column] : nil
164
+ auth_srid_ = @auth_srid_column ? obj_[@auth_srid_column] : nil
165
+ name_ = @name_column ? obj_[@name_column] : nil
166
+ description_ = @description_column ? obj_[@description_column] : nil
167
+ coord_sys_ = proj4_ = nil
168
+ if @srtext_column
169
+ coord_sys_ = CS.create_from_wkt(obj_[@srtext_column]) rescue nil
170
+ end
171
+ if @proj4text_column && Proj4.supported?
172
+ proj4_ = Proj4.create(obj_[@proj4text_column].strip) rescue nil
173
+ end
174
+ result_ = Entry.new(ident_, :authority => auth_name_, :authority_code => auth_srid_, :name => name_, :description => description_, :coord_sys => coord_sys_, :proj4 => proj4_)
175
+ @cache[ident_] = result_ if @cache
176
+ result_
177
+ end
178
+
179
+
180
+ # Clears the cache if a cache is active.
181
+
182
+ def clear_cache
183
+ @cache.clear if @cache
184
+ end
185
+
186
+
187
+ end
188
+
189
+
190
+ end
191
+
192
+ end
193
+
194
+ end