rgeo 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/History.rdoc +22 -0
  2. data/README.rdoc +124 -0
  3. data/Version +1 -0
  4. data/ext/geos_c_impl/extconf.rb +72 -0
  5. data/ext/geos_c_impl/factory.c +468 -0
  6. data/ext/geos_c_impl/factory.h +217 -0
  7. data/ext/geos_c_impl/geometry.c +644 -0
  8. data/ext/geos_c_impl/geometry.h +65 -0
  9. data/ext/geos_c_impl/geometry_collection.c +580 -0
  10. data/ext/geos_c_impl/geometry_collection.h +79 -0
  11. data/ext/geos_c_impl/globals.h +58 -0
  12. data/ext/geos_c_impl/line_string.c +468 -0
  13. data/ext/geos_c_impl/line_string.h +74 -0
  14. data/ext/geos_c_impl/main.c +65 -0
  15. data/ext/geos_c_impl/point.c +201 -0
  16. data/ext/geos_c_impl/point.h +77 -0
  17. data/ext/geos_c_impl/polygon.c +259 -0
  18. data/ext/geos_c_impl/polygon.h +76 -0
  19. data/ext/geos_c_impl/preface.h +42 -0
  20. data/lib/rgeo.rb +68 -0
  21. data/lib/rgeo/errors.rb +59 -0
  22. data/lib/rgeo/features.rb +89 -0
  23. data/lib/rgeo/features/curve.rb +155 -0
  24. data/lib/rgeo/features/factory.rb +191 -0
  25. data/lib/rgeo/features/geometry.rb +560 -0
  26. data/lib/rgeo/features/geometry_collection.rb +118 -0
  27. data/lib/rgeo/features/line.rb +65 -0
  28. data/lib/rgeo/features/line_string.rb +101 -0
  29. data/lib/rgeo/features/linear_ring.rb +65 -0
  30. data/lib/rgeo/features/multi_curve.rb +112 -0
  31. data/lib/rgeo/features/multi_line_string.rb +65 -0
  32. data/lib/rgeo/features/multi_point.rb +72 -0
  33. data/lib/rgeo/features/multi_polygon.rb +96 -0
  34. data/lib/rgeo/features/multi_surface.rb +115 -0
  35. data/lib/rgeo/features/point.rb +97 -0
  36. data/lib/rgeo/features/polygon.rb +141 -0
  37. data/lib/rgeo/features/surface.rb +121 -0
  38. data/lib/rgeo/geo_json.rb +58 -0
  39. data/lib/rgeo/geo_json/coder.rb +305 -0
  40. data/lib/rgeo/geo_json/entities.rb +284 -0
  41. data/lib/rgeo/geo_json/interface.rb +95 -0
  42. data/lib/rgeo/geography.rb +75 -0
  43. data/lib/rgeo/geography/common/geometry_collection_methods.rb +206 -0
  44. data/lib/rgeo/geography/common/geometry_methods.rb +92 -0
  45. data/lib/rgeo/geography/common/helper.rb +102 -0
  46. data/lib/rgeo/geography/common/line_string_methods.rb +187 -0
  47. data/lib/rgeo/geography/common/point_methods.rb +149 -0
  48. data/lib/rgeo/geography/common/polygon_methods.rb +122 -0
  49. data/lib/rgeo/geography/factories.rb +136 -0
  50. data/lib/rgeo/geography/factory.rb +246 -0
  51. data/lib/rgeo/geography/projected_window.rb +467 -0
  52. data/lib/rgeo/geography/simple_mercator/feature_classes.rb +320 -0
  53. data/lib/rgeo/geography/simple_mercator/feature_methods.rb +291 -0
  54. data/lib/rgeo/geography/simple_mercator/projector.rb +116 -0
  55. data/lib/rgeo/geography/simple_spherical/calculations.rb +70 -0
  56. data/lib/rgeo/geography/simple_spherical/geometry_collection_impl.rb +66 -0
  57. data/lib/rgeo/geography/simple_spherical/geometry_methods.rb +59 -0
  58. data/lib/rgeo/geography/simple_spherical/line_string_impl.rb +104 -0
  59. data/lib/rgeo/geography/simple_spherical/multi_line_string_impl.rb +67 -0
  60. data/lib/rgeo/geography/simple_spherical/multi_point_impl.rb +67 -0
  61. data/lib/rgeo/geography/simple_spherical/multi_polygon_impl.rb +67 -0
  62. data/lib/rgeo/geography/simple_spherical/point_impl.rb +85 -0
  63. data/lib/rgeo/geography/simple_spherical/polygon_impl.rb +66 -0
  64. data/lib/rgeo/geos.rb +72 -0
  65. data/lib/rgeo/geos/factory.rb +260 -0
  66. data/lib/rgeo/geos/impl_additions.rb +57 -0
  67. data/lib/rgeo/geos/interface.rb +74 -0
  68. data/lib/rgeo/version.rb +52 -0
  69. data/tests/geos/tc_factory.rb +91 -0
  70. data/tests/geos/tc_geometry_collection.rb +226 -0
  71. data/tests/geos/tc_line_string.rb +310 -0
  72. data/tests/geos/tc_misc.rb +72 -0
  73. data/tests/geos/tc_multi_line_string.rb +211 -0
  74. data/tests/geos/tc_multi_point.rb +202 -0
  75. data/tests/geos/tc_multi_polygon.rb +210 -0
  76. data/tests/geos/tc_point.rb +305 -0
  77. data/tests/geos/tc_polygon.rb +240 -0
  78. data/tests/simple_mercator/tc_point.rb +303 -0
  79. data/tests/simple_mercator/tc_window.rb +219 -0
  80. data/tests/tc_geojson.rb +230 -0
  81. data/tests/tc_oneoff.rb +61 -0
  82. metadata +162 -0
@@ -0,0 +1,217 @@
1
+ /*
2
+ -----------------------------------------------------------------------------
3
+
4
+ Factory and utility functions for GEOS wrapper
5
+
6
+ -----------------------------------------------------------------------------
7
+ Copyright 2010 Daniel Azuma
8
+
9
+ All rights reserved.
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ * Redistributions of source code must retain the above copyright notice,
15
+ this list of conditions and the following disclaimer.
16
+ * Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+ * Neither the name of the copyright holder, nor the names of any other
20
+ contributors to this software, may be used to endorse or promote products
21
+ derived from this software without specific prior written permission.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ POSSIBILITY OF SUCH DAMAGE.
34
+ -----------------------------------------------------------------------------
35
+ */
36
+
37
+
38
+ #ifndef RGEO_GEOS_FACTORY_INCLUDED
39
+ #define RGEO_GEOS_FACTORY_INCLUDED
40
+
41
+ #include <ruby.h>
42
+ #include <geos_c.h>
43
+
44
+ #ifdef __cplusplus
45
+ extern "C" {
46
+ #if 0
47
+ }
48
+ #endif
49
+ #endif
50
+
51
+
52
+ // Per-interpreter globals
53
+
54
+ typedef struct {
55
+ VALUE default_factory;
56
+ VALUE features_module;
57
+ VALUE geos_module;
58
+ } RGeo_Globals;
59
+
60
+
61
+ // Wrapped structure for Factory objects.
62
+ // A factory encapsulates the GEOS context, and GEOS serializer settings.
63
+ // It also stores the SRID for all geometries created by this factory,
64
+ // and the resolution for buffers created for this factory's geometries.
65
+ // Finally, it provides easy access to the globals.
66
+
67
+ typedef struct {
68
+ RGeo_Globals* globals;
69
+ GEOSContextHandle_t geos_context;
70
+ GEOSWKTReader* wkt_reader;
71
+ GEOSWKBReader* wkb_reader;
72
+ GEOSWKTWriter* wkt_writer;
73
+ GEOSWKBWriter* wkb_writer;
74
+ int flags;
75
+ int srid;
76
+ int buffer_resolution;
77
+ } RGeo_FactoryData;
78
+
79
+ #define RGEO_FACTORYFLAGS_LENIENT_MULTIPOLYGON 1
80
+
81
+
82
+ // Wrapped structure for Geometry objects.
83
+ // Includes a handle to the underlying GEOS geometry itself (which could
84
+ // be null for an uninitialized geometry).
85
+ // It also provides a handle to the factory that created this geometry.
86
+ // The klasses object is used by geometry collections. Its value is
87
+ // generally an array of the ruby classes for the colletion's elements,
88
+ // so that we can reproduce the exact class for those elements in cases
89
+ // where the class cannot be inferred directly from the GEOS type (as
90
+ // in Line objects, which have no GEOS type). Any array element, or the
91
+ // array itself, could be Qnil, indicating fall back to the default
92
+ // inferred from the GEOS type.
93
+
94
+ typedef struct {
95
+ GEOSGeometry* geom;
96
+ VALUE factory;
97
+ VALUE klasses;
98
+ } RGeo_GeometryData;
99
+
100
+
101
+ // Returns the RGeo_FactoryData* given a ruby Factory object
102
+ #define RGEO_FACTORY_DATA_PTR(factory) ((RGeo_FactoryData*)DATA_PTR(factory))
103
+
104
+ // Returns the RGeo_GeometryData* given a ruby Geometry object
105
+ #define RGEO_GEOMETRY_DATA_PTR(geometry) ((RGeo_GeometryData*)DATA_PTR(geometry))
106
+
107
+ // Returns a pointer to the globals given a ruby Factory object
108
+ #define RGEO_GLOBALS_FROM_FACTORY(factory) (RGEO_FACTORY_DATA_PTR(factory)->globals)
109
+
110
+ // Returns the GEOS context handle given a ruby Factory object
111
+ #define RGEO_CONTEXT_FROM_FACTORY(factory) (RGEO_FACTORY_DATA_PTR(factory)->geos_context)
112
+
113
+ // Returns the ruby Factory object given a ruby Geometry object
114
+ #define RGEO_FACTORY_FROM_GEOMETRY(geometry) (RGEO_GEOMETRY_DATA_PTR(geometry)->factory)
115
+
116
+ // Returns the klasses object given a ruby Geometry object
117
+ #define RGEO_KLASSES_FROM_GEOMETRY(geometry) (RGEO_GEOMETRY_DATA_PTR(geometry)->klasses)
118
+
119
+ // Returns the RGeo_FactoryData* given a ruby Geometry object
120
+ #define RGEO_FACTORY_DATA_FROM_GEOMETRY(geometry) RGEO_FACTORY_DATA_PTR(RGEO_FACTORY_FROM_GEOMETRY(geometry))
121
+
122
+ // Returns the GEOS geometry handle given a ruby Geometry object
123
+ #define RGEO_GET_GEOS_GEOMETRY(geometry) ((const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(geometry)->geom))
124
+
125
+ // Returns the GEOS context handle given a ruby Geometry object
126
+ #define RGEO_CONTEXT_FROM_GEOMETRY(geometry) RGEO_CONTEXT_FROM_FACTORY(RGEO_FACTORY_FROM_GEOMETRY(geometry))
127
+
128
+ // Returns a pointer to the globals given a ruby Geometry object
129
+ #define RGEO_GLOBALS_FROM_GEOMETRY(geometry) RGEO_GLOBALS_FROM_FACTORY(RGEO_FACTORY_FROM_GEOMETRY(geometry))
130
+
131
+
132
+ /*
133
+ Initializes the factory module. This should be called first in the
134
+ initialization process.
135
+ */
136
+ RGeo_Globals* rgeo_init_geos_factory();
137
+
138
+ /*
139
+ Given a GEOS geometry handle, wraps it in a ruby Geometry object of the
140
+ given klass. The geometry is then owned by the ruby object, so make sure
141
+ you clone the GEOS object first if something else thinks it owns it.
142
+ You may pass Qnil for the klass to have the klass auto-detected. (But
143
+ note that it cannot auto-detect the Line type because GEOS doesn't
144
+ explicitly represent that type-- it will come out as LineString.)
145
+ You may also pass a ruby Array for the klass if the geometry is a
146
+ collection of some sort. In this case, the array elements should be the
147
+ classes for the elements of the collection.
148
+ Returns Qnil if the wrapping failed for any reason.
149
+ */
150
+ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass);
151
+
152
+ /*
153
+ Same as rgeo_wrap_geos_geometry except that it wraps a clone of the
154
+ given geom, so the original geom doesn't change ownership.
155
+ */
156
+ VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VALUE klass);
157
+
158
+ /*
159
+ Gets the GEOS geometry for a given ruby Geometry object. If the given
160
+ ruby object is not a GEOS geometry implementation, it is converted to a
161
+ GEOS implementation first. The returned GEOS geometry is owned by rgeo,
162
+ and you should not dispose it or take ownership of it yourself.
163
+ */
164
+ const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj);
165
+
166
+ /*
167
+ Gets a GEOS geometry for a given ruby Geometry object. If the given
168
+ ruby object is not a GEOS geometry implementation, it is converted to a
169
+ GEOS implementation first. The returned GEOS geometry is owned by the
170
+ caller-- that is, if the original ruby object is a GEOS implementation,
171
+ the returned GEOS geometry is a clone of the original.
172
+ If the klasses parameters is not NULL, its referent is set to the
173
+ klasses saved in the original ruby Geometry object (if any), or to Qnil
174
+ if the original object is not a GEOS implementation. This is so that
175
+ you can use the result of this function to build a GEOS-backed clone
176
+ of the original geometry, or to include the given geometry in a
177
+ collection while keeping the klasses intact.
178
+ */
179
+ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(RGeo_Globals* globals, VALUE obj, VALUE* klasses);
180
+
181
+ /*
182
+ Returns 1 if the given ruby object is a GEOS Geometry implementation,
183
+ or 0 if not.
184
+ */
185
+ char rgeo_is_geos_object(VALUE obj);
186
+
187
+ /*
188
+ Gets the underlying GEOS geometry for a given ruby object. Returns NULL
189
+ if the given ruby object is not a GEOS geometry wrapper.
190
+ */
191
+ const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj);
192
+
193
+ /*
194
+ Compares the coordinate sequences for two given GEOS geometries.
195
+ The two given geometries MUST be of types backed directly by
196
+ coordinate sequences-- i.e. points or line strings.
197
+ Returns Qtrue if the two coordinate sequences are equal, Qfalse
198
+ if they are inequal, or Qnil if an error occurs.
199
+ */
200
+ VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2);
201
+
202
+ /*
203
+ Compares the ruby classes and geometry factories of the two given ruby
204
+ objects. Returns Qtrue if everything is equal (that is, the two objects
205
+ are of the same type and factory), or Qfalse otherwise.
206
+ */
207
+ VALUE rgeo_geos_klasses_and_factories_eql(VALUE obj1, VALUE obj2);
208
+
209
+
210
+ #ifdef __cplusplus
211
+ #if 0
212
+ {
213
+ #endif
214
+ }
215
+ #endif
216
+
217
+ #endif
@@ -0,0 +1,644 @@
1
+ /*
2
+ -----------------------------------------------------------------------------
3
+
4
+ Geometry base class methods for GEOS wrapper
5
+
6
+ -----------------------------------------------------------------------------
7
+ Copyright 2010 Daniel Azuma
8
+
9
+ All rights reserved.
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ * Redistributions of source code must retain the above copyright notice,
15
+ this list of conditions and the following disclaimer.
16
+ * Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+ * Neither the name of the copyright holder, nor the names of any other
20
+ contributors to this software, may be used to endorse or promote products
21
+ derived from this software without specific prior written permission.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ POSSIBILITY OF SUCH DAMAGE.
34
+ -----------------------------------------------------------------------------
35
+ */
36
+
37
+
38
+ #include "preface.h"
39
+
40
+ #ifdef RGEO_GEOS_SUPPORTED
41
+
42
+ #include <string.h>
43
+ #include <ruby.h>
44
+ #include <geos_c.h>
45
+
46
+ #include "factory.h"
47
+ #include "geometry.h"
48
+
49
+ #ifdef __cplusplus
50
+ extern "C" {
51
+ #if 0
52
+ }
53
+ #endif
54
+ #endif
55
+
56
+
57
+ /**** INTERNAL UTILITY FUNCTIONS ****/
58
+
59
+
60
+ // Determine the dimension of the given geometry. Empty collections have dimension -1.
61
+ // Recursively checks collection elemenets.
62
+
63
+ static int compute_dimension(GEOSContextHandle_t context, const GEOSGeometry* geom)
64
+ {
65
+ int result = -1;
66
+ int size, i;
67
+ if (geom) {
68
+ switch (GEOSGeomTypeId_r(context, geom)) {
69
+ case GEOS_POINT:
70
+ result = 0;
71
+ break;
72
+ case GEOS_MULTIPOINT:
73
+ if (!GEOSisEmpty_r(context, geom)) {
74
+ result = 0;
75
+ }
76
+ break;
77
+ case GEOS_LINESTRING:
78
+ case GEOS_LINEARRING:
79
+ result = 1;
80
+ break;
81
+ case GEOS_MULTILINESTRING:
82
+ if (!GEOSisEmpty_r(context, geom)) {
83
+ result = 1;
84
+ }
85
+ break;
86
+ case GEOS_POLYGON:
87
+ result = 2;
88
+ break;
89
+ case GEOS_MULTIPOLYGON:
90
+ if (!GEOSisEmpty_r(context, geom)) {
91
+ result = 2;
92
+ }
93
+ break;
94
+ case GEOS_GEOMETRYCOLLECTION:
95
+ size = GEOSGetNumGeometries_r(context, geom);
96
+ for (i=0; i<size; ++i) {
97
+ int dim = compute_dimension(context, GEOSGetGeometryN_r(context, geom, i));
98
+ if (dim > result) {
99
+ result = dim;
100
+ }
101
+ }
102
+ break;
103
+ }
104
+ }
105
+ return result;
106
+ }
107
+
108
+
109
+ /**** RUBY METHOD DEFINITIONS ****/
110
+
111
+
112
+ static VALUE method_geometry_initialized_p(VALUE self)
113
+ {
114
+ return RGEO_GET_GEOS_GEOMETRY(self) ? Qtrue : Qfalse;
115
+ }
116
+
117
+
118
+ static VALUE method_geometry_factory(VALUE self)
119
+ {
120
+ return RGEO_FACTORY_FROM_GEOMETRY(self);
121
+ }
122
+
123
+
124
+ static VALUE method_geometry_cast(VALUE self, VALUE type)
125
+ {
126
+ VALUE result = Qnil;
127
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
128
+ if (self_geom) {
129
+ char* my_type_str = GEOSGeomType_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
130
+ VALUE type_name = rb_funcall(type, rb_intern("name"), 0);
131
+ result = strcmp(my_type_str, StringValuePtr(type_name)) ? Qnil : self;
132
+ free(my_type_str);
133
+ }
134
+ return result;
135
+ }
136
+
137
+
138
+ static VALUE method_geometry_dimension(VALUE self)
139
+ {
140
+ VALUE result = Qnil;
141
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
142
+ if (self_geom) {
143
+ result = INT2NUM(compute_dimension(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom));
144
+ }
145
+ return result;
146
+ }
147
+
148
+
149
+ static VALUE method_geometry_geometry_type(VALUE self)
150
+ {
151
+ VALUE result = Qnil;
152
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
153
+ if (self_geom) {
154
+ result = rb_const_get_at(RGEO_GLOBALS_FROM_GEOMETRY(self)->features_module, rb_intern("Geometry"));
155
+ }
156
+ return result;
157
+ }
158
+
159
+
160
+ static VALUE method_geometry_srid(VALUE self)
161
+ {
162
+ VALUE result = Qnil;
163
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
164
+ if (self_geom) {
165
+ result = INT2NUM(GEOSGetSRID_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom));
166
+ }
167
+ return result;
168
+ }
169
+
170
+
171
+ static VALUE method_geometry_envelope(VALUE self)
172
+ {
173
+ VALUE result = Qnil;
174
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
175
+ if (self_geom) {
176
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSEnvelope_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom), Qnil);
177
+ }
178
+ return result;
179
+ }
180
+
181
+
182
+ static VALUE method_geometry_boundary(VALUE self)
183
+ {
184
+ VALUE result = Qnil;
185
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
186
+ if (self_geom) {
187
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSBoundary_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom), Qnil);
188
+ }
189
+ return result;
190
+ }
191
+
192
+
193
+ static VALUE method_geometry_as_text(VALUE self)
194
+ {
195
+ VALUE result = Qnil;
196
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
197
+ if (self_geom) {
198
+ GEOSWKTWriter* wkt_writer = RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->wkt_writer;
199
+ if (!wkt_writer) {
200
+ wkt_writer = GEOSWKTWriter_create_r(RGEO_CONTEXT_FROM_GEOMETRY(self));
201
+ RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->wkt_writer = wkt_writer;
202
+ }
203
+ char* str = GEOSWKTWriter_write_r(RGEO_CONTEXT_FROM_GEOMETRY(self), wkt_writer, self_geom);
204
+ if (str) {
205
+ result = rb_str_new2(str);
206
+ GEOSFree_r(RGEO_CONTEXT_FROM_GEOMETRY(self), str);
207
+ }
208
+ }
209
+ return result;
210
+ }
211
+
212
+
213
+ static VALUE method_geometry_as_binary(VALUE self)
214
+ {
215
+ VALUE result = Qnil;
216
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
217
+ if (self_geom) {
218
+ GEOSWKBWriter* wkb_writer = RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->wkb_writer;
219
+ if (!wkb_writer) {
220
+ wkb_writer = GEOSWKBWriter_create_r(RGEO_CONTEXT_FROM_GEOMETRY(self));
221
+ RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->wkb_writer = wkb_writer;
222
+ }
223
+ size_t size;
224
+ char* str = (char*)GEOSWKBWriter_write_r(RGEO_CONTEXT_FROM_GEOMETRY(self), wkb_writer, self_geom, &size);
225
+ if (str) {
226
+ result = rb_str_new(str, size);
227
+ GEOSFree_r(RGEO_CONTEXT_FROM_GEOMETRY(self), str);
228
+ }
229
+ }
230
+ return result;
231
+ }
232
+
233
+
234
+ static VALUE method_geometry_is_empty(VALUE self)
235
+ {
236
+ VALUE result = Qnil;
237
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
238
+ if (self_geom) {
239
+ char val = GEOSisEmpty_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
240
+ if (val == 0) {
241
+ result = Qfalse;
242
+ }
243
+ else if (val == 1) {
244
+ result = Qtrue;
245
+ }
246
+ }
247
+ return result;
248
+ }
249
+
250
+
251
+ static VALUE method_geometry_is_simple(VALUE self)
252
+ {
253
+ VALUE result = Qnil;
254
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
255
+ if (self_geom) {
256
+ char val = GEOSisSimple_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
257
+ if (val == 0) {
258
+ result = Qfalse;
259
+ }
260
+ else if (val == 1) {
261
+ result = Qtrue;
262
+ }
263
+ }
264
+ return result;
265
+ }
266
+
267
+
268
+ static VALUE method_geometry_equals(VALUE self, VALUE rhs)
269
+ {
270
+ VALUE result = Qnil;
271
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
272
+ if (self_geom) {
273
+ const GEOSGeometry* rhs_geom = rgeo_get_geos_geometry_safe(rhs);
274
+ if (rhs_geom) {
275
+ // GEOS has a bug where empty geometries are not spatially equal
276
+ // to each other. Work around this case first.
277
+ if (GEOSisEmpty_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom) == 1 &&
278
+ GEOSisEmpty_r(RGEO_CONTEXT_FROM_GEOMETRY(rhs), rhs_geom) == 1) {
279
+ result = Qtrue;
280
+ }
281
+ else {
282
+ char val = GEOSEquals_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
283
+ if (val == 0) {
284
+ result = Qfalse;
285
+ }
286
+ else if (val == 1) {
287
+ result = Qtrue;
288
+ }
289
+ }
290
+ }
291
+ }
292
+ return result;
293
+ }
294
+
295
+
296
+ static VALUE method_geometry_eql(VALUE self, VALUE rhs)
297
+ {
298
+ // This should be overridden by the subclass.
299
+ return self == rhs ? Qtrue : Qfalse;
300
+ }
301
+
302
+
303
+ static VALUE method_geometry_disjoint(VALUE self, VALUE rhs)
304
+ {
305
+ VALUE result = Qnil;
306
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
307
+ if (self_geom) {
308
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
309
+ if (rhs_geom) {
310
+ char val = GEOSDisjoint_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
311
+ if (val == 0) {
312
+ result = Qfalse;
313
+ }
314
+ else if (val == 1) {
315
+ result = Qtrue;
316
+ }
317
+ }
318
+ }
319
+ return result;
320
+ }
321
+
322
+
323
+ static VALUE method_geometry_intersects(VALUE self, VALUE rhs)
324
+ {
325
+ VALUE result = Qnil;
326
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
327
+ if (self_geom) {
328
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
329
+ if (rhs_geom) {
330
+ char val = GEOSIntersects_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
331
+ if (val == 0) {
332
+ result = Qfalse;
333
+ }
334
+ else if (val == 1) {
335
+ result = Qtrue;
336
+ }
337
+ }
338
+ }
339
+ return result;
340
+ }
341
+
342
+
343
+ static VALUE method_geometry_touches(VALUE self, VALUE rhs)
344
+ {
345
+ VALUE result = Qnil;
346
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
347
+ if (self_geom) {
348
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
349
+ if (rhs_geom) {
350
+ char val = GEOSTouches_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
351
+ if (val == 0) {
352
+ result = Qfalse;
353
+ }
354
+ else if (val == 1) {
355
+ result = Qtrue;
356
+ }
357
+ }
358
+ }
359
+ return result;
360
+ }
361
+
362
+
363
+ static VALUE method_geometry_crosses(VALUE self, VALUE rhs)
364
+ {
365
+ VALUE result = Qnil;
366
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
367
+ if (self_geom) {
368
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
369
+ if (rhs_geom) {
370
+ char val = GEOSCrosses_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
371
+ if (val == 0) {
372
+ result = Qfalse;
373
+ }
374
+ else if (val == 1) {
375
+ result = Qtrue;
376
+ }
377
+ }
378
+ }
379
+ return result;
380
+ }
381
+
382
+
383
+ static VALUE method_geometry_within(VALUE self, VALUE rhs)
384
+ {
385
+ VALUE result = Qnil;
386
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
387
+ if (self_geom) {
388
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
389
+ if (rhs_geom) {
390
+ char val = GEOSWithin_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
391
+ if (val == 0) {
392
+ result = Qfalse;
393
+ }
394
+ else if (val == 1) {
395
+ result = Qtrue;
396
+ }
397
+ }
398
+ }
399
+ return result;
400
+ }
401
+
402
+
403
+ static VALUE method_geometry_contains(VALUE self, VALUE rhs)
404
+ {
405
+ VALUE result = Qnil;
406
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
407
+ if (self_geom) {
408
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
409
+ if (rhs_geom) {
410
+ char val = GEOSContains_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
411
+ if (val == 0) {
412
+ result = Qfalse;
413
+ }
414
+ else if (val == 1) {
415
+ result = Qtrue;
416
+ }
417
+ }
418
+ }
419
+ return result;
420
+ }
421
+
422
+
423
+ static VALUE method_geometry_overlaps(VALUE self, VALUE rhs)
424
+ {
425
+ VALUE result = Qnil;
426
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
427
+ if (self_geom) {
428
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
429
+ if (rhs_geom) {
430
+ char val = GEOSOverlaps_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom);
431
+ if (val == 0) {
432
+ result = Qfalse;
433
+ }
434
+ else if (val == 1) {
435
+ result = Qtrue;
436
+ }
437
+ }
438
+ }
439
+ return result;
440
+ }
441
+
442
+
443
+ static VALUE method_geometry_relate(VALUE self, VALUE rhs, VALUE pattern)
444
+ {
445
+ VALUE result = Qnil;
446
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
447
+ if (self_geom) {
448
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
449
+ if (rhs_geom) {
450
+ char val = GEOSRelatePattern_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom, StringValuePtr(pattern));
451
+ if (val == 0) {
452
+ result = Qfalse;
453
+ }
454
+ else if (val == 1) {
455
+ result = Qtrue;
456
+ }
457
+ }
458
+ }
459
+ return result;
460
+ }
461
+
462
+
463
+ static VALUE method_geometry_distance(VALUE self, VALUE rhs)
464
+ {
465
+ VALUE result = Qnil;
466
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
467
+ if (self_geom) {
468
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
469
+ if (rhs_geom) {
470
+ double dist;
471
+ if (GEOSDistance_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom, &dist)) {
472
+ result = rb_float_new(dist);
473
+ }
474
+ }
475
+ }
476
+ return result;
477
+ }
478
+
479
+
480
+ static VALUE method_geometry_buffer(VALUE self, VALUE distance)
481
+ {
482
+ VALUE result = Qnil;
483
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
484
+ if (self_geom) {
485
+ int resolution = NUM2INT(RGEO_FACTORY_DATA_FROM_GEOMETRY(self)->buffer_resolution);
486
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSBuffer_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rb_num2dbl(distance), resolution), Qnil);
487
+ }
488
+ return result;
489
+ }
490
+
491
+
492
+ static VALUE method_geometry_convex_hull(VALUE self)
493
+ {
494
+ VALUE result = Qnil;
495
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
496
+ if (self_geom) {
497
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSConvexHull_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom), Qnil);
498
+ }
499
+ return result;
500
+ }
501
+
502
+
503
+ static VALUE method_geometry_intersection(VALUE self, VALUE rhs)
504
+ {
505
+ VALUE result = Qnil;
506
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
507
+ if (self_geom) {
508
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
509
+ if (rhs_geom) {
510
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSIntersection_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom), Qnil);
511
+ }
512
+ }
513
+ return result;
514
+ }
515
+
516
+
517
+ static VALUE method_geometry_union(VALUE self, VALUE rhs)
518
+ {
519
+ VALUE result = Qnil;
520
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
521
+ if (self_geom) {
522
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
523
+ if (rhs_geom) {
524
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSUnion_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom), Qnil);
525
+ }
526
+ }
527
+ return result;
528
+ }
529
+
530
+
531
+ static VALUE method_geometry_difference(VALUE self, VALUE rhs)
532
+ {
533
+ VALUE result = Qnil;
534
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
535
+ if (self_geom) {
536
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
537
+ if (rhs_geom) {
538
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSDifference_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom), Qnil);
539
+ }
540
+ }
541
+ return result;
542
+ }
543
+
544
+
545
+ static VALUE method_geometry_sym_difference(VALUE self, VALUE rhs)
546
+ {
547
+ VALUE result = Qnil;
548
+ const GEOSGeometry* self_geom = RGEO_GET_GEOS_GEOMETRY(self);
549
+ if (self_geom) {
550
+ const GEOSGeometry* rhs_geom = rgeo_convert_to_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), rhs);
551
+ if (rhs_geom) {
552
+ result = rgeo_wrap_geos_geometry(RGEO_FACTORY_FROM_GEOMETRY(self), GEOSSymDifference_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom, rhs_geom), Qnil);
553
+ }
554
+ }
555
+ return result;
556
+ }
557
+
558
+
559
+ static VALUE alloc_geometry(VALUE klass)
560
+ {
561
+ return rgeo_wrap_geos_geometry(Qnil, NULL, klass);
562
+ }
563
+
564
+
565
+ static VALUE method_geometry_initialize_copy(VALUE self, VALUE orig)
566
+ {
567
+ // Clear out any existing value
568
+ GEOSGeometry* self_geom = RGEO_GEOMETRY_DATA_PTR(self)->geom;
569
+ if (self_geom) {
570
+ GEOSGeom_destroy_r(RGEO_CONTEXT_FROM_GEOMETRY(self), self_geom);
571
+ RGEO_GEOMETRY_DATA_PTR(self)->geom = NULL;
572
+ RGEO_GEOMETRY_DATA_PTR(self)->factory = Qnil;
573
+ RGEO_GEOMETRY_DATA_PTR(self)->klasses = Qnil;
574
+ }
575
+
576
+ // Copy value from orig
577
+ const GEOSGeometry* geom = rgeo_get_geos_geometry_safe(orig);
578
+ if (geom) {
579
+ GEOSGeometry* clone_geom = GEOSGeom_clone_r(RGEO_CONTEXT_FROM_GEOMETRY(orig), geom);
580
+ if (clone_geom) {
581
+ GEOSSetSRID_r(RGEO_CONTEXT_FROM_GEOMETRY(orig), clone_geom, GEOSGetSRID_r(RGEO_CONTEXT_FROM_GEOMETRY(orig), geom));
582
+ RGEO_GEOMETRY_DATA_PTR(self)->geom = clone_geom;
583
+ RGEO_GEOMETRY_DATA_PTR(self)->factory = RGEO_FACTORY_FROM_GEOMETRY(orig);
584
+ RGEO_GEOMETRY_DATA_PTR(self)->klasses = RGEO_KLASSES_FROM_GEOMETRY(orig);
585
+ }
586
+ }
587
+ return self;
588
+ }
589
+
590
+
591
+ /**** INITIALIZATION FUNCTION ****/
592
+
593
+
594
+ void rgeo_init_geos_geometry(RGeo_Globals* globals)
595
+ {
596
+ VALUE geos_geometry_class = rb_define_class_under(globals->geos_module, "GeometryImpl", rb_cObject);
597
+
598
+ rb_define_alloc_func(geos_geometry_class, alloc_geometry);
599
+ rb_define_method(geos_geometry_class, "initialize_copy", method_geometry_initialize_copy, 1);
600
+ rb_define_method(geos_geometry_class, "initialized?", method_geometry_initialized_p, 0);
601
+ rb_define_method(geos_geometry_class, "factory", method_geometry_factory, 0);
602
+ rb_define_method(geos_geometry_class, "cast", method_geometry_cast, 1);
603
+ rb_define_method(geos_geometry_class, "dimension", method_geometry_dimension, 0);
604
+ rb_define_method(geos_geometry_class, "geometry_type", method_geometry_geometry_type, 0);
605
+ rb_define_method(geos_geometry_class, "srid", method_geometry_srid, 0);
606
+ rb_define_method(geos_geometry_class, "envelope", method_geometry_envelope, 0);
607
+ rb_define_method(geos_geometry_class, "boundary", method_geometry_boundary, 0);
608
+ rb_define_method(geos_geometry_class, "as_text", method_geometry_as_text, 0);
609
+ rb_define_method(geos_geometry_class, "to_s", method_geometry_as_text, 0);
610
+ rb_define_method(geos_geometry_class, "as_binary", method_geometry_as_binary, 0);
611
+ rb_define_method(geos_geometry_class, "is_empty?", method_geometry_is_empty, 0);
612
+ rb_define_method(geos_geometry_class, "is_simple?", method_geometry_is_simple, 0);
613
+ rb_define_method(geos_geometry_class, "equals?", method_geometry_equals, 1);
614
+ rb_define_method(geos_geometry_class, "==", method_geometry_equals, 1);
615
+ rb_define_method(geos_geometry_class, "eql?", method_geometry_eql, 1);
616
+ rb_define_method(geos_geometry_class, "disjoint?", method_geometry_disjoint, 1);
617
+ rb_define_method(geos_geometry_class, "intersects?", method_geometry_intersects, 1);
618
+ rb_define_method(geos_geometry_class, "touches?", method_geometry_touches, 1);
619
+ rb_define_method(geos_geometry_class, "crosses?", method_geometry_crosses, 1);
620
+ rb_define_method(geos_geometry_class, "within?", method_geometry_within, 1);
621
+ rb_define_method(geos_geometry_class, "contains?", method_geometry_contains, 1);
622
+ rb_define_method(geos_geometry_class, "overlaps?", method_geometry_overlaps, 1);
623
+ rb_define_method(geos_geometry_class, "relate?", method_geometry_relate, 2);
624
+ rb_define_method(geos_geometry_class, "distance", method_geometry_distance, 1);
625
+ rb_define_method(geos_geometry_class, "buffer", method_geometry_buffer, 1);
626
+ rb_define_method(geos_geometry_class, "convex_hull", method_geometry_convex_hull, 0);
627
+ rb_define_method(geos_geometry_class, "intersection", method_geometry_intersection, 1);
628
+ rb_define_method(geos_geometry_class, "*", method_geometry_intersection, 1);
629
+ rb_define_method(geos_geometry_class, "union", method_geometry_union, 1);
630
+ rb_define_method(geos_geometry_class, "+", method_geometry_union, 1);
631
+ rb_define_method(geos_geometry_class, "difference", method_geometry_difference, 1);
632
+ rb_define_method(geos_geometry_class, "-", method_geometry_difference, 1);
633
+ rb_define_method(geos_geometry_class, "sym_difference", method_geometry_sym_difference, 1);
634
+ }
635
+
636
+
637
+ #ifdef __cplusplus
638
+ #if 0
639
+ {
640
+ #endif
641
+ }
642
+ #endif
643
+
644
+ #endif