rgeo-dschee 0.5.4

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 (176) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +29 -0
  3. data/ext/geos_c_impl/coordinates.c +65 -0
  4. data/ext/geos_c_impl/coordinates.h +2 -0
  5. data/ext/geos_c_impl/extconf.rb +43 -0
  6. data/ext/geos_c_impl/factory.c +995 -0
  7. data/ext/geos_c_impl/factory.h +238 -0
  8. data/ext/geos_c_impl/geometry.c +1093 -0
  9. data/ext/geos_c_impl/geometry.h +23 -0
  10. data/ext/geos_c_impl/geometry_collection.c +757 -0
  11. data/ext/geos_c_impl/geometry_collection.h +46 -0
  12. data/ext/geos_c_impl/line_string.c +675 -0
  13. data/ext/geos_c_impl/line_string.h +32 -0
  14. data/ext/geos_c_impl/main.c +40 -0
  15. data/ext/geos_c_impl/point.c +236 -0
  16. data/ext/geos_c_impl/point.h +30 -0
  17. data/ext/geos_c_impl/polygon.c +359 -0
  18. data/ext/geos_c_impl/polygon.h +43 -0
  19. data/ext/geos_c_impl/preface.h +38 -0
  20. data/ext/proj4_c_impl/extconf.rb +62 -0
  21. data/ext/proj4_c_impl/main.c +315 -0
  22. data/lib/rgeo.rb +89 -0
  23. data/lib/rgeo/cartesian.rb +25 -0
  24. data/lib/rgeo/cartesian/analysis.rb +77 -0
  25. data/lib/rgeo/cartesian/bounding_box.rb +398 -0
  26. data/lib/rgeo/cartesian/calculations.rb +113 -0
  27. data/lib/rgeo/cartesian/factory.rb +347 -0
  28. data/lib/rgeo/cartesian/feature_classes.rb +100 -0
  29. data/lib/rgeo/cartesian/feature_methods.rb +88 -0
  30. data/lib/rgeo/cartesian/interface.rb +135 -0
  31. data/lib/rgeo/coord_sys.rb +43 -0
  32. data/lib/rgeo/coord_sys/cs/entities.rb +1315 -0
  33. data/lib/rgeo/coord_sys/cs/factories.rb +148 -0
  34. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +272 -0
  35. data/lib/rgeo/coord_sys/proj4.rb +293 -0
  36. data/lib/rgeo/coord_sys/srs_database/interface.rb +115 -0
  37. data/lib/rgeo/coord_sys/srs_database/proj4_data.rb +140 -0
  38. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +62 -0
  39. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +63 -0
  40. data/lib/rgeo/error.rb +27 -0
  41. data/lib/rgeo/feature.rb +54 -0
  42. data/lib/rgeo/feature/curve.rb +111 -0
  43. data/lib/rgeo/feature/factory.rb +278 -0
  44. data/lib/rgeo/feature/factory_generator.rb +96 -0
  45. data/lib/rgeo/feature/geometry.rb +624 -0
  46. data/lib/rgeo/feature/geometry_collection.rb +95 -0
  47. data/lib/rgeo/feature/line.rb +26 -0
  48. data/lib/rgeo/feature/line_string.rb +60 -0
  49. data/lib/rgeo/feature/linear_ring.rb +26 -0
  50. data/lib/rgeo/feature/mixins.rb +143 -0
  51. data/lib/rgeo/feature/multi_curve.rb +71 -0
  52. data/lib/rgeo/feature/multi_line_string.rb +26 -0
  53. data/lib/rgeo/feature/multi_point.rb +33 -0
  54. data/lib/rgeo/feature/multi_polygon.rb +57 -0
  55. data/lib/rgeo/feature/multi_surface.rb +73 -0
  56. data/lib/rgeo/feature/point.rb +84 -0
  57. data/lib/rgeo/feature/polygon.rb +97 -0
  58. data/lib/rgeo/feature/surface.rb +79 -0
  59. data/lib/rgeo/feature/types.rb +284 -0
  60. data/lib/rgeo/geographic.rb +40 -0
  61. data/lib/rgeo/geographic/factory.rb +450 -0
  62. data/lib/rgeo/geographic/interface.rb +489 -0
  63. data/lib/rgeo/geographic/proj4_projector.rb +58 -0
  64. data/lib/rgeo/geographic/projected_feature_classes.rb +107 -0
  65. data/lib/rgeo/geographic/projected_feature_methods.rb +212 -0
  66. data/lib/rgeo/geographic/projected_window.rb +383 -0
  67. data/lib/rgeo/geographic/simple_mercator_projector.rb +110 -0
  68. data/lib/rgeo/geographic/spherical_feature_classes.rb +100 -0
  69. data/lib/rgeo/geographic/spherical_feature_methods.rb +134 -0
  70. data/lib/rgeo/geographic/spherical_math.rb +188 -0
  71. data/lib/rgeo/geos.rb +89 -0
  72. data/lib/rgeo/geos/capi_factory.rb +470 -0
  73. data/lib/rgeo/geos/capi_feature_classes.rb +129 -0
  74. data/lib/rgeo/geos/ffi_factory.rb +592 -0
  75. data/lib/rgeo/geos/ffi_feature_classes.rb +83 -0
  76. data/lib/rgeo/geos/ffi_feature_methods.rb +574 -0
  77. data/lib/rgeo/geos/interface.rb +202 -0
  78. data/lib/rgeo/geos/utils.rb +74 -0
  79. data/lib/rgeo/geos/zm_factory.rb +405 -0
  80. data/lib/rgeo/geos/zm_feature_classes.rb +80 -0
  81. data/lib/rgeo/geos/zm_feature_methods.rb +344 -0
  82. data/lib/rgeo/impl_helper.rb +19 -0
  83. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +185 -0
  84. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +61 -0
  85. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +146 -0
  86. data/lib/rgeo/impl_helper/basic_point_methods.rb +104 -0
  87. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +87 -0
  88. data/lib/rgeo/impl_helper/math.rb +14 -0
  89. data/lib/rgeo/impl_helper/utils.rb +29 -0
  90. data/lib/rgeo/version.rb +3 -0
  91. data/lib/rgeo/wkrep.rb +37 -0
  92. data/lib/rgeo/wkrep/wkb_generator.rb +201 -0
  93. data/lib/rgeo/wkrep/wkb_parser.rb +251 -0
  94. data/lib/rgeo/wkrep/wkt_generator.rb +207 -0
  95. data/lib/rgeo/wkrep/wkt_parser.rb +415 -0
  96. data/lib/rgeo/yaml.rb +23 -0
  97. data/test/cartesian_analysis_test.rb +65 -0
  98. data/test/cartesian_bbox_test.rb +123 -0
  99. data/test/common/factory_tests.rb +78 -0
  100. data/test/common/geometry_collection_tests.rb +237 -0
  101. data/test/common/line_string_tests.rb +330 -0
  102. data/test/common/multi_line_string_tests.rb +182 -0
  103. data/test/common/multi_point_tests.rb +200 -0
  104. data/test/common/multi_polygon_tests.rb +191 -0
  105. data/test/common/point_tests.rb +370 -0
  106. data/test/common/polygon_tests.rb +261 -0
  107. data/test/coord_sys/ogc_cs_test.rb +342 -0
  108. data/test/coord_sys/proj4_srs_data_test.rb +41 -0
  109. data/test/coord_sys/proj4_test.rb +150 -0
  110. data/test/coord_sys/sr_org_test.rb +32 -0
  111. data/test/coord_sys/url_reader_test.rb +42 -0
  112. data/test/geos_capi/factory_test.rb +31 -0
  113. data/test/geos_capi/geometry_collection_test.rb +24 -0
  114. data/test/geos_capi/line_string_test.rb +24 -0
  115. data/test/geos_capi/misc_test.rb +116 -0
  116. data/test/geos_capi/multi_line_string_test.rb +24 -0
  117. data/test/geos_capi/multi_point_test.rb +24 -0
  118. data/test/geos_capi/multi_polygon_test.rb +39 -0
  119. data/test/geos_capi/parsing_unparsing_test.rb +40 -0
  120. data/test/geos_capi/point_test.rb +72 -0
  121. data/test/geos_capi/polygon_test.rb +154 -0
  122. data/test/geos_capi/zmfactory_test.rb +57 -0
  123. data/test/geos_ffi/factory_test.rb +31 -0
  124. data/test/geos_ffi/geometry_collection_test.rb +24 -0
  125. data/test/geos_ffi/line_string_test.rb +24 -0
  126. data/test/geos_ffi/misc_test.rb +63 -0
  127. data/test/geos_ffi/multi_line_string_test.rb +24 -0
  128. data/test/geos_ffi/multi_point_test.rb +24 -0
  129. data/test/geos_ffi/multi_polygon_test.rb +33 -0
  130. data/test/geos_ffi/parsing_unparsing_test.rb +41 -0
  131. data/test/geos_ffi/point_test.rb +77 -0
  132. data/test/geos_ffi/polygon_test.rb +46 -0
  133. data/test/geos_ffi/zmfactory_test.rb +58 -0
  134. data/test/mixins_test.rb +141 -0
  135. data/test/oneoff_test.rb +26 -0
  136. data/test/projected_geographic/factory_test.rb +25 -0
  137. data/test/projected_geographic/geometry_collection_test.rb +24 -0
  138. data/test/projected_geographic/line_string_test.rb +24 -0
  139. data/test/projected_geographic/multi_line_string_test.rb +26 -0
  140. data/test/projected_geographic/multi_point_test.rb +30 -0
  141. data/test/projected_geographic/multi_polygon_test.rb +25 -0
  142. data/test/projected_geographic/point_test.rb +51 -0
  143. data/test/projected_geographic/polygon_test.rb +24 -0
  144. data/test/simple_cartesian/calculations_test.rb +99 -0
  145. data/test/simple_cartesian/factory_test.rb +27 -0
  146. data/test/simple_cartesian/geometry_collection_test.rb +30 -0
  147. data/test/simple_cartesian/line_string_test.rb +31 -0
  148. data/test/simple_cartesian/multi_line_string_test.rb +28 -0
  149. data/test/simple_cartesian/multi_point_test.rb +31 -0
  150. data/test/simple_cartesian/multi_polygon_test.rb +31 -0
  151. data/test/simple_cartesian/point_test.rb +50 -0
  152. data/test/simple_cartesian/polygon_test.rb +28 -0
  153. data/test/simple_mercator/factory_test.rb +25 -0
  154. data/test/simple_mercator/geometry_collection_test.rb +24 -0
  155. data/test/simple_mercator/line_string_test.rb +24 -0
  156. data/test/simple_mercator/multi_line_string_test.rb +26 -0
  157. data/test/simple_mercator/multi_point_test.rb +29 -0
  158. data/test/simple_mercator/multi_polygon_test.rb +25 -0
  159. data/test/simple_mercator/point_test.rb +55 -0
  160. data/test/simple_mercator/polygon_test.rb +24 -0
  161. data/test/simple_mercator/window_test.rb +173 -0
  162. data/test/spherical_geographic/calculations_test.rb +167 -0
  163. data/test/spherical_geographic/factory_test.rb +27 -0
  164. data/test/spherical_geographic/geometry_collection_test.rb +31 -0
  165. data/test/spherical_geographic/line_string_test.rb +31 -0
  166. data/test/spherical_geographic/multi_line_string_test.rb +29 -0
  167. data/test/spherical_geographic/multi_point_test.rb +31 -0
  168. data/test/spherical_geographic/multi_polygon_test.rb +31 -0
  169. data/test/spherical_geographic/point_test.rb +78 -0
  170. data/test/spherical_geographic/polygon_test.rb +28 -0
  171. data/test/types_test.rb +42 -0
  172. data/test/wkrep/wkb_generator_test.rb +185 -0
  173. data/test/wkrep/wkb_parser_test.rb +293 -0
  174. data/test/wkrep/wkt_generator_test.rb +294 -0
  175. data/test/wkrep/wkt_parser_test.rb +412 -0
  176. metadata +386 -0
@@ -0,0 +1,202 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GEOS toplevel interface
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geos
9
+ class << self
10
+ # Returns true if the CAPI GEOS implementation is supported.
11
+
12
+ def capi_supported?
13
+ CAPI_SUPPORTED
14
+ end
15
+
16
+ # Returns true if the FFI GEOS implementation is supported.
17
+
18
+ def ffi_supported?
19
+ FFI_SUPPORTED
20
+ end
21
+
22
+ # Returns true if any GEOS implementation is supported.
23
+ # If this returns false, GEOS features are not available at all.
24
+
25
+ def supported?
26
+ FFI_SUPPORTED || CAPI_SUPPORTED
27
+ end
28
+
29
+ # Returns true if the given feature is a CAPI GEOS feature, or if
30
+ # the given factory is a CAPI GEOS factory.
31
+
32
+ def is_capi_geos?(object_)
33
+ CAPI_SUPPORTED &&
34
+ (CAPIFactory === object_ || CAPIGeometryMethods === object_ ||
35
+ ZMFactory === object_ && CAPIFactory === object_.z_factory ||
36
+ ZMGeometryMethods === object_ && CAPIGeometryMethods === object_.z_geometry)
37
+ end
38
+
39
+ # Returns true if the given feature is an FFI GEOS feature, or if
40
+ # the given factory is an FFI GEOS factory.
41
+
42
+ def is_ffi_geos?(object_)
43
+ FFI_SUPPORTED &&
44
+ (FFIFactory === object_ || FFIGeometryMethods === object_ ||
45
+ ZMFactory === object_ && FFIFactory === object_.z_factory ||
46
+ ZMGeometryMethods === object_ && FFIGeometryMethods === object_.z_geometry)
47
+ end
48
+
49
+ # Returns true if the given feature is a GEOS feature, or if the given
50
+ # factory is a GEOS factory. Does not distinguish between CAPI and FFI.
51
+
52
+ def is_geos?(object_)
53
+ CAPI_SUPPORTED && (CAPIFactory === object_ || CAPIGeometryMethods === object_) ||
54
+ FFI_SUPPORTED && (FFIFactory === object_ || FFIGeometryMethods === object_) ||
55
+ ZMFactory === object_ || ZMGeometryMethods === object_
56
+ end
57
+
58
+ # Returns the GEOS library version as a string of the format "x.y.z".
59
+ # Returns nil if GEOS is not available.
60
+
61
+ def version
62
+ unless defined?(@version)
63
+ if ::RGeo::Geos::CAPI_SUPPORTED
64
+ @version = ::RGeo::Geos::CAPIFactory._geos_version.freeze
65
+ elsif ::RGeo::Geos::FFI_SUPPORTED
66
+ @version = ::Geos::FFIGeos.GEOSversion.sub(/-CAPI-.*$/, "").freeze
67
+ else
68
+ @version = nil
69
+ end
70
+ end
71
+ @version
72
+ end
73
+
74
+ # The preferred native interface. This is the native interface
75
+ # used by default when a factory is created.
76
+ # Supported values are <tt>:capi</tt> and <tt>:ffi</tt>.
77
+ #
78
+ # This is set automatically when RGeo loads, to <tt>:capi</tt>
79
+ # if the CAPI interface is available, otheriwse to <tt>:ffi</tt>
80
+ # if FFI is available, otherwise to nil if no GEOS interface is
81
+ # available. You can override this setting if you want to prefer
82
+ # FFI over CAPI.
83
+
84
+ attr_accessor :preferred_native_interface
85
+
86
+ # Returns a factory for the GEOS implementation.
87
+ # Returns nil if the GEOS implementation is not supported.
88
+ #
89
+ # Note that GEOS does not natively support 4-dimensional data
90
+ # (i.e. both z and m values). However, RGeo's GEOS wrapper does
91
+ # provide a 4-dimensional factory that utilizes an extra native
92
+ # GEOS object to handle the extra coordinate. Hence, a factory
93
+ # configured with both Z and M support will work, but will be
94
+ # slower than a 2-dimensional or 3-dimensional factory.
95
+ #
96
+ # Options include:
97
+ #
98
+ # [<tt>:native_interface</tt>]
99
+ # Specifies which native interface to use. Possible values are
100
+ # <tt>:capi</tt> and <tt>:ffi</tt>. The default is the value
101
+ # of the preferred_native_interface.
102
+ # [<tt>:uses_lenient_multi_polygon_assertions</tt>]
103
+ # If set to true, assertion checking on MultiPolygon is disabled.
104
+ # This may speed up creation of MultiPolygon objects, at the
105
+ # expense of not doing the proper checking for OGC MultiPolygon
106
+ # compliance. See RGeo::Feature::MultiPolygon for details on
107
+ # the MultiPolygon assertions. Default is false. Also called
108
+ # <tt>:lenient_multi_polygon_assertions</tt>.
109
+ # [<tt>:buffer_resolution</tt>]
110
+ # The resolution of buffers around geometries created by this
111
+ # factory. This controls the number of line segments used to
112
+ # approximate curves. The default is 1, which causes, for
113
+ # example, the buffer around a point to be approximated by a
114
+ # 4-sided polygon. A resolution of 2 would cause that buffer
115
+ # to be approximated by an 8-sided polygon. The exact behavior
116
+ # for different kinds of buffers is defined by GEOS.
117
+ # [<tt>:srid</tt>]
118
+ # Set the SRID returned by geometries created by this factory.
119
+ # Default is 0.
120
+ # [<tt>:proj4</tt>]
121
+ # The coordinate system in Proj4 format, either as a
122
+ # CoordSys::Proj4 object or as a string or hash representing the
123
+ # proj4 format. Optional.
124
+ # [<tt>:coord_sys</tt>]
125
+ # The coordinate system in OGC form, either as a subclass of
126
+ # CoordSys::CS::CoordinateSystem, or as a string in WKT format.
127
+ # Optional.
128
+ # [<tt>:srs_database</tt>]
129
+ # Optional. If provided, the value should be an implementation of
130
+ # CoordSys::SRSDatabase::Interface. If both this and an SRID are
131
+ # provided, they are used to look up the proj4 and coord_sys
132
+ # objects from a spatial reference system database.
133
+ # [<tt>:has_z_coordinate</tt>]
134
+ # Support <tt>z_coordinate</tt>. Default is false.
135
+ # [<tt>:has_m_coordinate</tt>]
136
+ # Support <tt>m_coordinate</tt>. Default is false.
137
+ # [<tt>:wkt_parser</tt>]
138
+ # Configure the parser for WKT. You may either pass a hash of
139
+ # configuration parameters for WKRep::WKTParser.new, or the
140
+ # special value <tt>:geos</tt>, indicating to use the native
141
+ # GEOS parser. Default is the empty hash, indicating the default
142
+ # configuration for WKRep::WKTParser.
143
+ # Note that the special <tt>:geos</tt> value is not supported for
144
+ # ZM factories, since GEOS currently can't handle ZM natively.
145
+ # [<tt>:wkb_parser</tt>]
146
+ # Configure the parser for WKB. You may either pass a hash of
147
+ # configuration parameters for WKRep::WKBParser.new, or the
148
+ # special value <tt>:geos</tt>, indicating to use the native
149
+ # GEOS parser. Default is the empty hash, indicating the default
150
+ # configuration for WKRep::WKBParser.
151
+ # Note that the special <tt>:geos</tt> value is not supported for
152
+ # ZM factories, since GEOS currently can't handle ZM natively.
153
+ # [<tt>:wkt_generator</tt>]
154
+ # Configure the generator for WKT. You may either pass a hash of
155
+ # configuration parameters for WKRep::WKTGenerator.new, or the
156
+ # special value <tt>:geos</tt>, indicating to use the native
157
+ # GEOS generator. Default is <tt>{:convert_case => :upper}</tt>.
158
+ # Note that the special <tt>:geos</tt> value is not supported for
159
+ # ZM factories, since GEOS currently can't handle ZM natively.
160
+ # [<tt>:wkb_generator</tt>]
161
+ # Configure the generator for WKB. You may either pass a hash of
162
+ # configuration parameters for WKRep::WKBGenerator.new, or the
163
+ # special value <tt>:geos</tt>, indicating to use the native
164
+ # GEOS generator. Default is the empty hash, indicating the
165
+ # default configuration for WKRep::WKBGenerator.
166
+ # Note that the special <tt>:geos</tt> value is not supported for
167
+ # ZM factories, since GEOS currently can't handle ZM natively.
168
+ # [<tt>:auto_prepare</tt>]
169
+ # Request an auto-prepare strategy. Supported values are
170
+ # <tt>:simple</tt> and <tt>:disabled</tt>. The former (which is
171
+ # the default) generates a prepared geometry the second time an
172
+ # operation that would benefit from it is called. The latter
173
+ # never automatically generates a prepared geometry (unless you
174
+ # generate one explicitly using the <tt>prepare!</tt> method).
175
+
176
+ def factory(opts_ = {})
177
+ if supported?
178
+ native_interface_ = opts_[:native_interface] || Geos.preferred_native_interface
179
+ if opts_[:has_z_coordinate] && opts_[:has_m_coordinate]
180
+ ZMFactory.new(opts_)
181
+ elsif native_interface_ == :ffi
182
+ FFIFactory.new(opts_)
183
+ else
184
+ CAPIFactory.create(opts_)
185
+ end
186
+ end
187
+ end
188
+
189
+ # Returns a Feature::FactoryGenerator that creates Geos-backed
190
+ # factories. The given options are used as the default options.
191
+ #
192
+ # A common case for this is to provide the <tt>:srs_database</tt>
193
+ # as a default. Then, the factory generator need only be passed
194
+ # an SRID and it will automatically fetch the appropriate Proj4
195
+ # and CoordSys objects.
196
+
197
+ def factory_generator(defaults_ = {})
198
+ ::Proc.new { |c_| factory(defaults_.merge(c_)) }
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,74 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Various Geos-related internal utilities
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geos
9
+ module Utils # :nodoc:
10
+ class << self
11
+ def ffi_coord_seqs_equal?(cs1_, cs2_, check_z_)
12
+ len1_ = cs1_.length
13
+ len2_ = cs2_.length
14
+ if len1_ == len2_
15
+ (0...len1_).each do |i_|
16
+ return false unless cs1_.get_x(i_) == cs2_.get_x(i_) &&
17
+ cs1_.get_y(i_) == cs2_.get_y(i_) &&
18
+ (!check_z_ || cs1_.get_z(i_) == cs2_.get_z(i_))
19
+ end
20
+ true
21
+ else
22
+ false
23
+ end
24
+ end
25
+
26
+ def ffi_compute_dimension(geom_)
27
+ result_ = -1
28
+ case geom_.type_id
29
+ when ::Geos::GeomTypes::GEOS_POINT
30
+ result_ = 0
31
+ when ::Geos::GeomTypes::GEOS_MULTIPOINT
32
+ result_ = 0 unless geom_.empty?
33
+ when ::Geos::GeomTypes::GEOS_LINESTRING, ::Geos::GeomTypes::GEOS_LINEARRING
34
+ result_ = 1
35
+ when ::Geos::GeomTypes::GEOS_MULTILINESTRING
36
+ result_ = 1 unless geom_.empty?
37
+ when ::Geos::GeomTypes::GEOS_POLYGON
38
+ result_ = 2
39
+ when ::Geos::GeomTypes::GEOS_MULTIPOLYGON
40
+ result_ = 2 unless geom_.empty?
41
+ when ::Geos::GeomTypes::GEOS_GEOMETRYCOLLECTION
42
+ geom_.each do |g_|
43
+ dim_ = ffi_compute_dimension(g_)
44
+ result_ = dim_ if result_ < dim_
45
+ end
46
+ end
47
+ result_
48
+ end
49
+
50
+ def ffi_coord_seq_hash(cs_, hash_ = 0)
51
+ (0...cs_.length).inject(hash_) do |_h_, i_|
52
+ [hash_, cs_.get_x(i_), cs_.get_y(i_), cs_.get_z(i_)].hash
53
+ end
54
+ end
55
+
56
+ def _init
57
+ if FFI_SUPPORTED
58
+ @ffi_supports_prepared_level_1 = ::Geos::FFIGeos.respond_to?(:GEOSPreparedContains_r)
59
+ @ffi_supports_prepared_level_2 = ::Geos::FFIGeos.respond_to?(:GEOSPreparedDisjoint_r)
60
+ @ffi_supports_set_output_dimension = ::Geos::FFIGeos.respond_to?(:GEOSWKTWriter_setOutputDimension_r)
61
+ end
62
+ @psych_wkt_generator = WKRep::WKTGenerator.new(convert_case: :upper)
63
+ @marshal_wkb_generator = WKRep::WKBGenerator.new
64
+ end
65
+
66
+ attr_reader :ffi_supports_prepared_level_1
67
+ attr_reader :ffi_supports_prepared_level_2
68
+ attr_reader :ffi_supports_set_output_dimension
69
+ attr_reader :psych_wkt_generator
70
+ attr_reader :marshal_wkb_generator
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,405 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # GEOS zm factory implementation
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+
7
+ module RGeo
8
+ module Geos
9
+ # A factory for Geos that handles both Z and M.
10
+
11
+ class ZMFactory
12
+ include Feature::Factory::Instance
13
+
14
+ # :stopdoc:
15
+
16
+ TYPE_KLASSES = {
17
+ Feature::Point => ZMPointImpl,
18
+ Feature::LineString => ZMLineStringImpl,
19
+ Feature::Line => ZMLineImpl,
20
+ Feature::LinearRing => ZMLinearRingImpl,
21
+ Feature::Polygon => ZMPolygonImpl,
22
+ Feature::GeometryCollection => ZMGeometryCollectionImpl,
23
+ Feature::MultiPoint => ZMMultiPointImpl,
24
+ Feature::MultiLineString => ZMMultiLineStringImpl,
25
+ Feature::MultiPolygon => ZMMultiPolygonImpl
26
+ }.freeze
27
+
28
+ # :startdoc:
29
+
30
+ class << self
31
+ # Create a new factory. Returns nil if the GEOS implementation is
32
+ # not supported.
33
+
34
+ def create(opts_ = {})
35
+ return nil unless Geos.supported?
36
+ new(opts_)
37
+ end
38
+ end
39
+
40
+ def initialize(opts_ = {}) # :nodoc:
41
+ proj4_ = opts_[:proj4]
42
+ coord_sys_ = opts_[:coord_sys]
43
+ srid_ = opts_[:srid]
44
+ if (!proj4_ || !coord_sys_) && srid_ && (db_ = opts_[:srs_database])
45
+ entry_ = db_.get(srid_.to_i)
46
+ if entry_
47
+ proj4_ ||= entry_.proj4
48
+ coord_sys_ ||= entry_.coord_sys
49
+ end
50
+ end
51
+ srid_ ||= coord_sys_.authority_code if coord_sys_
52
+ config_ = {
53
+ uses_lenient_multi_polygon_assertions: opts_[:lenient_multi_polygon_assertions] ||
54
+ opts_[:uses_lenient_multi_polygon_assertions],
55
+ buffer_resolution: opts_[:buffer_resolution], auto_prepare: opts_[:auto_prepare],
56
+ wkt_generator: opts_[:wkt_generator], wkt_parser: opts_[:wkt_parser],
57
+ wkb_generator: opts_[:wkb_generator], wkb_parser: opts_[:wkb_parser],
58
+ srid: srid_.to_i, proj4: proj4_, coord_sys: coord_sys_
59
+ }
60
+ native_interface_ = opts_[:native_interface] || Geos.preferred_native_interface
61
+ if native_interface_ == :ffi
62
+ @zfactory = FFIFactory.new(config_.merge(has_z_coordinate: true))
63
+ @mfactory = FFIFactory.new(config_.merge(has_m_coordinate: true))
64
+ else
65
+ @zfactory = CAPIFactory.create(config_.merge(has_z_coordinate: true))
66
+ @mfactory = CAPIFactory.create(config_.merge(has_m_coordinate: true))
67
+ end
68
+
69
+ wkt_generator_ = opts_[:wkt_generator]
70
+ case wkt_generator_
71
+ when ::Hash
72
+ @wkt_generator = WKRep::WKTGenerator.new(wkt_generator_)
73
+ else
74
+ @wkt_generator = WKRep::WKTGenerator.new(convert_case: :upper)
75
+ end
76
+ wkb_generator_ = opts_[:wkb_generator]
77
+ case wkb_generator_
78
+ when ::Hash
79
+ @wkb_generator = WKRep::WKBGenerator.new(wkb_generator_)
80
+ else
81
+ @wkb_generator = WKRep::WKBGenerator.new
82
+ end
83
+ wkt_parser_ = opts_[:wkt_parser]
84
+ case wkt_parser_
85
+ when ::Hash
86
+ @wkt_parser = WKRep::WKTParser.new(self, wkt_parser_)
87
+ else
88
+ @wkt_parser = WKRep::WKTParser.new(self)
89
+ end
90
+ wkb_parser_ = opts_[:wkb_parser]
91
+ case wkb_parser_
92
+ when ::Hash
93
+ @wkb_parser = WKRep::WKBParser.new(self, wkb_parser_)
94
+ else
95
+ @wkb_parser = WKRep::WKBParser.new(self)
96
+ end
97
+ end
98
+
99
+ # Marshal support
100
+
101
+ def marshal_dump # :nodoc:
102
+ hash_ = {
103
+ "srid" => @zfactory.srid,
104
+ "bufr" => @zfactory.buffer_resolution,
105
+ "wktg" => @wkt_generator._properties,
106
+ "wkbg" => @wkb_generator._properties,
107
+ "wktp" => @wkt_parser._properties,
108
+ "wkbp" => @wkb_parser._properties,
109
+ "lmpa" => @zfactory.lenient_multi_polygon_assertions?,
110
+ "apre" => @zfactory.property(:auto_prepare) == :simple,
111
+ "nffi" => @zfactory.is_a?(FFIFactory)
112
+ }
113
+ proj4_ = @zfactory.proj4
114
+ coord_sys_ = @zfactory.coord_sys
115
+ hash_["proj4"] = proj4_.marshal_dump if proj4_
116
+ hash_["cs"] = coord_sys_.to_wkt if coord_sys_
117
+ hash_
118
+ end
119
+
120
+ def marshal_load(data_) # :nodoc:
121
+ if CoordSys::Proj4.supported? && (proj4_data_ = data_["proj4"])
122
+ proj4_ = CoordSys::Proj4.allocate
123
+ proj4_.marshal_load(proj4_data_)
124
+ else
125
+ proj4_ = nil
126
+ end
127
+ if (coord_sys_data_ = data_["cs"])
128
+ coord_sys_ = CoordSys::CS.create_from_wkt(coord_sys_data_)
129
+ else
130
+ coord_sys_ = nil
131
+ end
132
+ initialize(
133
+ native_interface: (data_["nffi"] ? :ffi : :capi),
134
+ has_z_coordinate: data_["hasz"],
135
+ has_m_coordinate: data_["hasm"],
136
+ srid: data_["srid"],
137
+ buffer_resolution: data_["bufr"],
138
+ wkt_generator: ImplHelper::Utils.symbolize_hash(data_["wktg"]),
139
+ wkb_generator: ImplHelper::Utils.symbolize_hash(data_["wkbg"]),
140
+ wkt_parser: ImplHelper::Utils.symbolize_hash(data_["wktp"]),
141
+ wkb_parser: ImplHelper::Utils.symbolize_hash(data_["wkbp"]),
142
+ uses_lenient_multi_polygon_assertions: data_["lmpa"],
143
+ auto_prepare: (data_["apre"] ? :simple : :disabled),
144
+ proj4: proj4_,
145
+ coord_sys: coord_sys_
146
+ )
147
+ end
148
+
149
+ # Psych support
150
+
151
+ def encode_with(coder_) # :nodoc:
152
+ coder_["srid"] = @zfactory.srid
153
+ coder_["buffer_resolution"] = @zfactory.buffer_resolution
154
+ coder_["lenient_multi_polygon_assertions"] = @zfactory.lenient_multi_polygon_assertions?
155
+ coder_["wkt_generator"] = @wkt_generator._properties
156
+ coder_["wkb_generator"] = @wkb_generator._properties
157
+ coder_["wkt_parser"] = @wkt_parser._properties
158
+ coder_["wkb_parser"] = @wkb_parser._properties
159
+ coder_["auto_prepare"] = @zfactory.property(:auto_prepare).to_s
160
+ coder_["native_interface"] = @zfactory.is_a?(FFIFactory) ? "ffi" : "capi"
161
+ if (proj4_ = @zfactory.proj4)
162
+ str_ = proj4_.original_str || proj4_.canonical_str
163
+ coder_["proj4"] = proj4_.radians? ? { "proj4" => str_, "radians" => true } : str_
164
+ end
165
+ if (coord_sys_ = @zfactory.coord_sys)
166
+ coder_["coord_sys"] = coord_sys_.to_wkt
167
+ end
168
+ end
169
+
170
+ def init_with(coder_) # :nodoc:
171
+ if (proj4_data_ = coder_["proj4"])
172
+ if proj4_data_.is_a?(::Hash)
173
+ proj4_ = CoordSys::Proj4.create(proj4_data_["proj4"], radians: proj4_data_["radians"])
174
+ else
175
+ proj4_ = CoordSys::Proj4.create(proj4_data_.to_s)
176
+ end
177
+ else
178
+ proj4_ = nil
179
+ end
180
+ if (coord_sys_data_ = coder_["cs"])
181
+ coord_sys_ = CoordSys::CS.create_from_wkt(coord_sys_data_.to_s)
182
+ else
183
+ coord_sys_ = nil
184
+ end
185
+ initialize(
186
+ native_interface: coder_["native_interface"] == "ffi" ? :ffi : :capi,
187
+ has_z_coordinate: coder_["has_z_coordinate"],
188
+ has_m_coordinate: coder_["has_m_coordinate"],
189
+ srid: coder_["srid"],
190
+ buffer_resolution: coder_["buffer_resolution"],
191
+ wkt_generator: ImplHelper::Utils.symbolize_hash(coder_["wkt_generator"]),
192
+ wkb_generator: ImplHelper::Utils.symbolize_hash(coder_["wkb_generator"]),
193
+ wkt_parser: ImplHelper::Utils.symbolize_hash(coder_["wkt_parser"]),
194
+ wkb_parser: ImplHelper::Utils.symbolize_hash(coder_["wkb_parser"]),
195
+ auto_prepare: coder_["auto_prepare"] == "disabled" ? :disabled : :simple,
196
+ uses_lenient_multi_polygon_assertions: coder_["lenient_multi_polygon_assertions"],
197
+ proj4: proj4_,
198
+ coord_sys: coord_sys_
199
+ )
200
+ end
201
+
202
+ # Returns the SRID of geometries created by this factory.
203
+
204
+ def srid
205
+ @zfactory.srid
206
+ end
207
+
208
+ # Returns the resolution used by buffer calculations on geometries
209
+ # created by this factory
210
+
211
+ def buffer_resolution
212
+ @zfactory.buffer_resolution
213
+ end
214
+
215
+ # Returns true if this factory is lenient with MultiPolygon assertions
216
+
217
+ def lenient_multi_polygon_assertions?
218
+ @zfactory.lenient_multi_polygon_assertions?
219
+ end
220
+
221
+ # Returns the z-only factory corresponding to this factory.
222
+
223
+ def z_factory
224
+ @zfactory
225
+ end
226
+
227
+ # Returns the m-only factory corresponding to this factory.
228
+
229
+ def m_factory
230
+ @mfactory
231
+ end
232
+
233
+ # Factory equivalence test.
234
+
235
+ def eql?(rhs_)
236
+ rhs_.is_a?(ZMFactory) && rhs_.z_factory == @zfactory
237
+ end
238
+ alias_method :==, :eql?
239
+
240
+ # Standard hash code
241
+
242
+ def hash
243
+ @hash ||= [@zfactory, @mfactory].hash
244
+ end
245
+
246
+ # See ::RGeo::Feature::Factory#property
247
+
248
+ def property(name_)
249
+ case name_
250
+ when :has_z_coordinate, :has_m_coordinate, :is_cartesian
251
+ true
252
+ end
253
+ end
254
+
255
+ # See ::RGeo::Feature::Factory#parse_wkt
256
+
257
+ def parse_wkt(str_)
258
+ @wkt_parser.parse(str_)
259
+ end
260
+
261
+ # See ::RGeo::Feature::Factory#parse_wkb
262
+
263
+ def parse_wkb(str_)
264
+ @wkb_parser.parse(str_)
265
+ end
266
+
267
+ # See ::RGeo::Feature::Factory#point
268
+
269
+ def point(x_, y_, z_ = 0, m_ = 0)
270
+ _create_feature(ZMPointImpl, @zfactory.point(x_, y_, z_), @mfactory.point(x_, y_, m_))
271
+ end
272
+
273
+ # See ::RGeo::Feature::Factory#line_string
274
+
275
+ def line_string(points_)
276
+ _create_feature(ZMLineStringImpl, @zfactory.line_string(points_), @mfactory.line_string(points_))
277
+ end
278
+
279
+ # See ::RGeo::Feature::Factory#line
280
+
281
+ def line(start_, end_)
282
+ _create_feature(ZMLineImpl, @zfactory.line(start_, end_), @mfactory.line(start_, end_))
283
+ end
284
+
285
+ # See ::RGeo::Feature::Factory#linear_ring
286
+
287
+ def linear_ring(points_)
288
+ _create_feature(ZMLinearRingImpl, @zfactory.linear_ring(points_), @mfactory.linear_ring(points_))
289
+ end
290
+
291
+ # See ::RGeo::Feature::Factory#polygon
292
+
293
+ def polygon(outer_ring_, inner_rings_ = nil)
294
+ _create_feature(ZMPolygonImpl, @zfactory.polygon(outer_ring_, inner_rings_), @mfactory.polygon(outer_ring_, inner_rings_))
295
+ end
296
+
297
+ # See ::RGeo::Feature::Factory#collection
298
+
299
+ def collection(elems_)
300
+ _create_feature(ZMGeometryCollectionImpl, @zfactory.collection(elems_), @mfactory.collection(elems_))
301
+ end
302
+
303
+ # See ::RGeo::Feature::Factory#multi_point
304
+
305
+ def multi_point(elems_)
306
+ _create_feature(ZMMultiPointImpl, @zfactory.multi_point(elems_), @mfactory.multi_point(elems_))
307
+ end
308
+
309
+ # See ::RGeo::Feature::Factory#multi_line_string
310
+
311
+ def multi_line_string(elems_)
312
+ _create_feature(ZMMultiLineStringImpl, @zfactory.multi_line_string(elems_), @mfactory.multi_line_string(elems_))
313
+ end
314
+
315
+ # See ::RGeo::Feature::Factory#multi_polygon
316
+
317
+ def multi_polygon(elems_)
318
+ _create_feature(ZMMultiPolygonImpl, @zfactory.multi_polygon(elems_), @mfactory.multi_polygon(elems_))
319
+ end
320
+
321
+ # See ::RGeo::Feature::Factory#proj4
322
+
323
+ def proj4
324
+ @zfactory.proj4
325
+ end
326
+
327
+ # See ::RGeo::Feature::Factory#coord_sys
328
+
329
+ def coord_sys
330
+ @zfactory.coord_sys
331
+ end
332
+
333
+ # See ::RGeo::Feature::Factory#override_cast
334
+
335
+ def override_cast(original_, ntype_, flags_)
336
+ return nil unless Geos.supported?
337
+ keep_subtype_ = flags_[:keep_subtype]
338
+ # force_new_ = flags_[:force_new]
339
+ project_ = flags_[:project]
340
+ type_ = original_.geometry_type
341
+ ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
342
+ case original_
343
+ when ZMGeometryMethods
344
+ # Optimization if we're just changing factories, but to
345
+ # another ZM factory.
346
+ if original_.factory != self && ntype_ == type_ &&
347
+ (!project_ || original_.factory.proj4 == @proj4)
348
+ zresult_ = original_.z_geometry.dup
349
+ zresult_._set_factory(@zfactory)
350
+ mresult_ = original_.m_geometry.dup
351
+ mresult_._set_factory(@mfactory)
352
+ return original_.class.create(self, zresult_, mresult_)
353
+ end
354
+ # LineString conversion optimization.
355
+ if (original_.factory != self || ntype_ != type_) &&
356
+ (!project_ || original_.factory.proj4 == @proj4) &&
357
+ type_.subtype_of?(Feature::LineString) && ntype_.subtype_of?(Feature::LineString)
358
+ klass_ = Factory::IMPL_CLASSES[ntype_]
359
+ zresult_ = klass_._copy_from(@zfactory, original_.z_geometry)
360
+ mresult_ = klass_._copy_from(@mfactory, original_.m_geometry)
361
+ return ZMLineStringImpl.create(self, zresult_, mresult_)
362
+ end
363
+ end
364
+ false
365
+ end
366
+
367
+ def _create_feature(klass_, zgeometry_, mgeometry_) # :nodoc:
368
+ klass_ ||= TYPE_KLASSES[zgeometry_.geometry_type] || ZMGeometryImpl
369
+ zgeometry_ && mgeometry_ ? klass_.new(self, zgeometry_, mgeometry_) : nil
370
+ end
371
+
372
+ def _marshal_wkb_generator # :nodoc:
373
+ unless defined?(@marshal_wkb_generator)
374
+ @marshal_wkb_generator = ::RGeo::WKRep::WKBGenerator.new(
375
+ type_format: :wkb12)
376
+ end
377
+ @marshal_wkb_generator
378
+ end
379
+
380
+ def _marshal_wkb_parser # :nodoc:
381
+ unless defined?(@marshal_wkb_parser)
382
+ @marshal_wkb_parser = ::RGeo::WKRep::WKBParser.new(self,
383
+ support_wkb12: true)
384
+ end
385
+ @marshal_wkb_parser
386
+ end
387
+
388
+ def _psych_wkt_generator # :nodoc:
389
+ unless defined?(@psych_wkt_generator)
390
+ @psych_wkt_generator = ::RGeo::WKRep::WKTGenerator.new(
391
+ tag_format: :wkt12)
392
+ end
393
+ @psych_wkt_generator
394
+ end
395
+
396
+ def _psych_wkt_parser # :nodoc:
397
+ unless defined?(@psych_wkt_parser)
398
+ @psych_wkt_parser = ::RGeo::WKRep::WKTParser.new(self,
399
+ support_wkt12: true, support_ewkt: true)
400
+ end
401
+ @psych_wkt_parser
402
+ end
403
+ end
404
+ end
405
+ end