rgeo 0.1.10

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