schleyfox-rgeo 0.2.5

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 (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