rgeo 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ /*
2
+ Geometry base class methods for GEOS wrapper
3
+ */
4
+
5
+
6
+ #ifndef RGEO_GEOS_GEOMETRY_INCLUDED
7
+ #define RGEO_GEOS_GEOMETRY_INCLUDED
8
+
9
+ #include "factory.h"
10
+
11
+ RGEO_BEGIN_C
12
+
13
+
14
+ /*
15
+ Initializes the geometry module. This should be called after the factory
16
+ module is initialized, but before any of the other modules.
17
+ */
18
+ void rgeo_init_geos_geometry(RGeo_Globals* globals);
19
+
20
+
21
+ RGEO_END_C
22
+
23
+ #endif
@@ -0,0 +1,757 @@
1
+ /*
2
+ Geometry collection methods for GEOS wrapper
3
+ */
4
+
5
+
6
+ #include "preface.h"
7
+
8
+ #ifdef RGEO_GEOS_SUPPORTED
9
+
10
+ #include <ruby.h>
11
+ #include <geos_c.h>
12
+
13
+ #include "factory.h"
14
+ #include "geometry.h"
15
+ #include "line_string.h"
16
+ #include "polygon.h"
17
+ #include "geometry_collection.h"
18
+
19
+ #include "coordinates.h"
20
+
21
+ RGEO_BEGIN_C
22
+
23
+
24
+ /**** INTERNAL IMPLEMENTATION OF CREATE ****/
25
+
26
+
27
+ // Main implementation of the "create" class method for geometry collections.
28
+ // You must pass in the correct GEOS geometry type ID.
29
+
30
+ static VALUE create_geometry_collection(VALUE module, int type, VALUE factory, VALUE array)
31
+ {
32
+ VALUE result;
33
+ unsigned int len;
34
+ GEOSGeometry** geoms;
35
+ RGeo_FactoryData* factory_data;
36
+ GEOSContextHandle_t geos_context;
37
+ VALUE klass;
38
+ unsigned int i;
39
+ unsigned int j;
40
+ VALUE klasses;
41
+ VALUE cast_type;
42
+ GEOSGeometry* geom;
43
+ GEOSGeometry* collection;
44
+ char problem;
45
+ GEOSGeometry* igeom;
46
+ GEOSGeometry* jgeom;
47
+
48
+ result = Qnil;
49
+ Check_Type(array, T_ARRAY);
50
+ len = (unsigned int)RARRAY_LEN(array);
51
+ geoms = ALLOC_N(GEOSGeometry*, len == 0 ? 1 : len);
52
+ if (geoms) {
53
+ factory_data = RGEO_FACTORY_DATA_PTR(factory);
54
+ geos_context = factory_data->geos_context;
55
+ klasses = Qnil;
56
+ cast_type = Qnil;
57
+ switch (type) {
58
+ case GEOS_MULTIPOINT:
59
+ cast_type = factory_data->globals->feature_point;
60
+ break;
61
+ case GEOS_MULTILINESTRING:
62
+ cast_type = factory_data->globals->feature_line_string;
63
+ break;
64
+ case GEOS_MULTIPOLYGON:
65
+ cast_type = factory_data->globals->feature_polygon;
66
+ break;
67
+ }
68
+ for (i=0; i<len; ++i) {
69
+ geom = rgeo_convert_to_detached_geos_geometry(rb_ary_entry(array, i), factory, cast_type, &klass);
70
+ if (!geom) {
71
+ break;
72
+ }
73
+ geoms[i] = geom;
74
+ if (!NIL_P(klass) && NIL_P(klasses)) {
75
+ klasses = rb_ary_new2(len);
76
+ for (j=0; j<i; ++j) {
77
+ rb_ary_push(klasses, Qnil);
78
+ }
79
+ }
80
+ if (!NIL_P(klasses)) {
81
+ rb_ary_push(klasses, klass);
82
+ }
83
+ }
84
+ if (i != len) {
85
+ for (j=0; j<i; ++j) {
86
+ GEOSGeom_destroy_r(geos_context, geoms[j]);
87
+ }
88
+ }
89
+ else {
90
+ collection = GEOSGeom_createCollection_r(geos_context, type, geoms, len);
91
+ // Due to a limitation of GEOS, the MultiPolygon assertions are not checked.
92
+ // We do that manually here.
93
+ if (collection && type == GEOS_MULTIPOLYGON && (factory_data->flags & 1) == 0) {
94
+ problem = 0;
95
+ for (i=1; i<len; ++i) {
96
+ for (j=0; j<i; ++j) {
97
+ igeom = geoms[i];
98
+ jgeom = geoms[j];
99
+ problem = GEOSRelatePattern_r(geos_context, igeom, jgeom, "2********");
100
+ if (problem) {
101
+ break;
102
+ }
103
+ problem = GEOSRelatePattern_r(geos_context, igeom, jgeom, "****1****");
104
+ if (problem) {
105
+ break;
106
+ }
107
+ }
108
+ if (problem) {
109
+ break;
110
+ }
111
+ }
112
+ if (problem) {
113
+ GEOSGeom_destroy_r(geos_context, collection);
114
+ collection = NULL;
115
+ }
116
+ }
117
+ if (collection) {
118
+ result = rgeo_wrap_geos_geometry(factory, collection, module);
119
+ RGEO_GEOMETRY_DATA_PTR(result)->klasses = klasses;
120
+ }
121
+ // NOTE: We are assuming that GEOS will do its own cleanup of the
122
+ // element geometries if it fails to create the collection, so we
123
+ // are not doing that ourselves. If that turns out not to be the
124
+ // case, this will be a memory leak.
125
+ }
126
+ free(geoms);
127
+ }
128
+
129
+ return result;
130
+ }
131
+
132
+
133
+ /**** RUBY METHOD DEFINITIONS ****/
134
+
135
+
136
+ static VALUE method_geometry_collection_eql(VALUE self, VALUE rhs)
137
+ {
138
+ VALUE result;
139
+ RGeo_GeometryData* self_data;
140
+
141
+ result = rgeo_geos_klasses_and_factories_eql(self, rhs);
142
+ if (RTEST(result)) {
143
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
144
+ result = rgeo_geos_geometry_collections_eql(self_data->geos_context, self_data->geom, RGEO_GEOMETRY_DATA_PTR(rhs)->geom, RGEO_FACTORY_DATA_PTR(self_data->factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M);
145
+ }
146
+ return result;
147
+ }
148
+
149
+
150
+ static VALUE method_geometry_collection_hash(VALUE self)
151
+ {
152
+ st_index_t hash;
153
+ RGeo_GeometryData* self_data;
154
+ VALUE factory;
155
+
156
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
157
+ factory = self_data->factory;
158
+ hash = rb_hash_start(0);
159
+ hash = rgeo_geos_objbase_hash(factory,
160
+ RGEO_FACTORY_DATA_PTR(factory)->globals->feature_geometry_collection, hash);
161
+ hash = rgeo_geos_geometry_collection_hash(self_data->geos_context, self_data->geom, hash);
162
+ return LONG2FIX(rb_hash_end(hash));
163
+ }
164
+
165
+
166
+ static VALUE method_geometry_collection_geometry_type(VALUE self)
167
+ {
168
+ VALUE result;
169
+ RGeo_GeometryData* self_data;
170
+
171
+ result = Qnil;
172
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
173
+ if (self_data->geom) {
174
+ result = RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->feature_geometry_collection;
175
+ }
176
+ return result;
177
+ }
178
+
179
+
180
+ static VALUE method_geometry_collection_num_geometries(VALUE self)
181
+ {
182
+ VALUE result;
183
+ RGeo_GeometryData* self_data;
184
+ const GEOSGeometry* self_geom;
185
+
186
+ result = Qnil;
187
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
188
+ self_geom = self_data->geom;
189
+ if (self_geom) {
190
+ result = INT2NUM(GEOSGetNumGeometries_r(self_data->geos_context, self_geom));
191
+ }
192
+ return result;
193
+ }
194
+
195
+
196
+ static VALUE impl_geometry_n(VALUE self, VALUE n, char allow_negatives)
197
+ {
198
+ VALUE result;
199
+ RGeo_GeometryData* self_data;
200
+ const GEOSGeometry* self_geom;
201
+ VALUE klasses;
202
+ int i;
203
+ int len;
204
+
205
+ result = Qnil;
206
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
207
+ self_geom = self_data->geom;
208
+ if (self_geom) {
209
+ klasses = self_data->klasses;
210
+ i = NUM2INT(n);
211
+ if (allow_negatives || i >= 0) {
212
+ GEOSContextHandle_t self_context = self_data->geos_context;
213
+ len = GEOSGetNumGeometries_r(self_context, self_geom);
214
+ if (i < 0) {
215
+ i += len;
216
+ }
217
+ if (i >= 0 && i < len) {
218
+ result = rgeo_wrap_geos_geometry_clone(self_data->factory,
219
+ GEOSGetGeometryN_r(self_context, self_geom, i),
220
+ NIL_P(klasses) ? Qnil : rb_ary_entry(klasses, i));
221
+ }
222
+ }
223
+ }
224
+ return result;
225
+ }
226
+
227
+
228
+ static VALUE method_geometry_collection_geometry_n(VALUE self, VALUE n)
229
+ {
230
+ return impl_geometry_n(self, n, 0);
231
+ }
232
+
233
+
234
+ static VALUE method_geometry_collection_brackets(VALUE self, VALUE n)
235
+ {
236
+ return impl_geometry_n(self, n, 1);
237
+ }
238
+
239
+
240
+ static VALUE method_geometry_collection_each(VALUE self)
241
+ {
242
+ RGeo_GeometryData* self_data;
243
+ const GEOSGeometry* self_geom;
244
+ int len;
245
+ VALUE klasses;
246
+ int i;
247
+ VALUE elem;
248
+ const GEOSGeometry* elem_geom;
249
+
250
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
251
+
252
+ if (rb_block_given_p()) {
253
+ self_geom = self_data->geom;
254
+ if (self_geom) {
255
+ GEOSContextHandle_t self_context = self_data->geos_context;
256
+ len = GEOSGetNumGeometries_r(self_context, self_geom);
257
+ if (len > 0) {
258
+ klasses = self_data->klasses;
259
+ for (i=0; i<len; ++i) {
260
+ elem_geom = GEOSGetGeometryN_r(self_context, self_geom, i);
261
+ elem = rgeo_wrap_geos_geometry_clone(self_data->factory, elem_geom, NIL_P(klasses) ? Qnil : rb_ary_entry(klasses, i));
262
+ if (!NIL_P(elem)) {
263
+ rb_yield(elem);
264
+ }
265
+ }
266
+ }
267
+ }
268
+ return self;
269
+ }
270
+ else {
271
+ return rb_funcall(self, RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->id_enum_for, 0);
272
+ }
273
+ }
274
+
275
+ static VALUE method_multi_point_geometry_type(VALUE self)
276
+ {
277
+ VALUE result;
278
+ RGeo_GeometryData* self_data;
279
+
280
+ result = Qnil;
281
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
282
+ if (self_data->geom) {
283
+ result = RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->feature_multi_point;
284
+ }
285
+ return result;
286
+ }
287
+
288
+
289
+ static VALUE method_multi_point_hash(VALUE self)
290
+ {
291
+ st_index_t hash;
292
+ RGeo_GeometryData* self_data;
293
+ VALUE factory;
294
+
295
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
296
+ factory = self_data->factory;
297
+ hash = rb_hash_start(0);
298
+ hash = rgeo_geos_objbase_hash(factory,
299
+ RGEO_FACTORY_DATA_PTR(factory)->globals->feature_multi_point, hash);
300
+ hash = rgeo_geos_geometry_collection_hash(self_data->geos_context, self_data->geom, hash);
301
+ return LONG2FIX(rb_hash_end(hash));
302
+ }
303
+
304
+
305
+ static VALUE method_multi_point_coordinates(VALUE self)
306
+ {
307
+ VALUE result = Qnil;
308
+ RGeo_GeometryData* self_data;
309
+ const GEOSGeometry* self_geom;
310
+ GEOSContextHandle_t context;
311
+ const GEOSCoordSequence* coord_sequence;
312
+
313
+ const GEOSGeometry* point;
314
+ unsigned int count;
315
+ unsigned int i;
316
+ int zCoordinate;
317
+
318
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
319
+ self_geom = self_data->geom;
320
+
321
+ if(self_geom) {
322
+ zCoordinate = RGEO_FACTORY_DATA_PTR(self_data->factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
323
+ context = self_data->geos_context;
324
+ count = GEOSGetNumGeometries_r(context, self_geom);
325
+ result = rb_ary_new2(count);
326
+ for(i = 0; i < count; ++i) {
327
+ point = GEOSGetGeometryN_r(context, self_geom, i);
328
+ coord_sequence = GEOSGeom_getCoordSeq_r(context, point);
329
+ rb_ary_push(result, rb_ary_pop(extract_points_from_coordinate_sequence(context, coord_sequence, zCoordinate)));
330
+ }
331
+ }
332
+
333
+ return result;
334
+ }
335
+
336
+
337
+ static VALUE method_multi_line_string_geometry_type(VALUE self)
338
+ {
339
+ VALUE result;
340
+ RGeo_GeometryData* self_data;
341
+
342
+ result = Qnil;
343
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
344
+ if (self_data->geom) {
345
+ result = RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->feature_multi_line_string;
346
+ }
347
+ return result;
348
+ }
349
+
350
+
351
+ static VALUE method_multi_line_string_hash(VALUE self)
352
+ {
353
+ st_index_t hash;
354
+ RGeo_GeometryData* self_data;
355
+ VALUE factory;
356
+
357
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
358
+ factory = self_data->factory;
359
+ hash = rb_hash_start(0);
360
+ hash = rgeo_geos_objbase_hash(factory,
361
+ RGEO_FACTORY_DATA_PTR(factory)->globals->feature_multi_line_string, hash);
362
+ hash = rgeo_geos_geometry_collection_hash(self_data->geos_context, self_data->geom, hash);
363
+ return LONG2FIX(rb_hash_end(hash));
364
+ }
365
+
366
+
367
+ static VALUE method_multi_line_string_coordinates(VALUE self)
368
+ {
369
+ VALUE result = Qnil;
370
+ RGeo_GeometryData* self_data;
371
+ const GEOSGeometry* self_geom;
372
+ GEOSContextHandle_t context;
373
+ const GEOSCoordSequence* coord_sequence;
374
+
375
+ const GEOSGeometry* line_string;
376
+ unsigned int count;
377
+ unsigned int i;
378
+ int zCoordinate;
379
+
380
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
381
+ self_geom = self_data->geom;
382
+
383
+ if(self_geom) {
384
+ zCoordinate = RGEO_FACTORY_DATA_PTR(self_data->factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
385
+ context = self_data->geos_context;
386
+ count = GEOSGetNumGeometries_r(context, self_geom);
387
+ result = rb_ary_new2(count);
388
+ for(i = 0; i < count; ++i) {
389
+ line_string = GEOSGetGeometryN_r(context, self_geom, i);
390
+ coord_sequence = GEOSGeom_getCoordSeq_r(context, line_string);
391
+ rb_ary_push(result, extract_points_from_coordinate_sequence(context, coord_sequence, zCoordinate));
392
+ }
393
+ }
394
+
395
+ return result;
396
+ }
397
+
398
+ static VALUE method_multi_line_string_length(VALUE self)
399
+ {
400
+ VALUE result;
401
+ RGeo_GeometryData* self_data;
402
+ const GEOSGeometry* self_geom;
403
+ double len;
404
+
405
+ result = Qnil;
406
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
407
+ self_geom = self_data->geom;
408
+ if (self_geom) {
409
+ if (GEOSLength_r(self_data->geos_context, self_geom, &len)) {
410
+ result = rb_float_new(len);
411
+ }
412
+ }
413
+ return result;
414
+ }
415
+
416
+
417
+ static VALUE method_multi_line_string_is_closed(VALUE self)
418
+ {
419
+ VALUE result;
420
+ RGeo_GeometryData* self_data;
421
+ const GEOSGeometry* self_geom;
422
+ GEOSContextHandle_t self_context;
423
+ int len;
424
+ int i;
425
+ const GEOSGeometry* geom;
426
+
427
+ result = Qnil;
428
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
429
+ self_geom = self_data->geom;
430
+ if (self_geom) {
431
+ self_context = self_data->geos_context;
432
+ result = Qtrue;
433
+ len = GEOSGetNumGeometries_r(self_context, self_geom);
434
+ if (len > 0) {
435
+ for (i=0; i<len; ++i) {
436
+ geom = GEOSGetGeometryN_r(self_context, self_geom, i);
437
+ if (geom) {
438
+ result = rgeo_is_geos_line_string_closed(self_context, self_geom);
439
+ if (result != Qtrue) {
440
+ break;
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+ return result;
447
+ }
448
+
449
+
450
+ static VALUE method_multi_polygon_geometry_type(VALUE self)
451
+ {
452
+ VALUE result;
453
+ RGeo_GeometryData* self_data;
454
+
455
+ result = Qnil;
456
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
457
+ if (self_data->geom) {
458
+ result = RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->feature_multi_polygon;
459
+ }
460
+ return result;
461
+ }
462
+
463
+
464
+ static VALUE method_multi_polygon_hash(VALUE self)
465
+ {
466
+ st_index_t hash;
467
+ RGeo_GeometryData* self_data;
468
+ VALUE factory;
469
+
470
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
471
+ factory = self_data->factory;
472
+ hash = rb_hash_start(0);
473
+ hash = rgeo_geos_objbase_hash(factory,
474
+ RGEO_FACTORY_DATA_PTR(factory)->globals->feature_multi_polygon, hash);
475
+ hash = rgeo_geos_geometry_collection_hash(self_data->geos_context, self_data->geom, hash);
476
+ return LONG2FIX(rb_hash_end(hash));
477
+ }
478
+
479
+
480
+ static VALUE method_multi_polygon_coordinates(VALUE self)
481
+ {
482
+ VALUE result = Qnil;
483
+ RGeo_GeometryData* self_data;
484
+ const GEOSGeometry* self_geom;
485
+ GEOSContextHandle_t context;
486
+
487
+ const GEOSGeometry* poly;
488
+ unsigned int count;
489
+ unsigned int i;
490
+ int zCoordinate;
491
+
492
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
493
+ self_geom = self_data->geom;
494
+
495
+ if(self_geom) {
496
+ zCoordinate = RGEO_FACTORY_DATA_PTR(self_data->factory)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
497
+ context = self_data->geos_context;
498
+ count = GEOSGetNumGeometries_r(context, self_geom);
499
+ result = rb_ary_new2(count);
500
+ for(i = 0; i < count; ++i) {
501
+ poly = GEOSGetGeometryN_r(context, self_geom, i);
502
+ rb_ary_push(result, extract_points_from_polygon(context, poly, zCoordinate));
503
+ }
504
+ }
505
+
506
+ return result;
507
+ }
508
+
509
+
510
+ static VALUE method_multi_polygon_area(VALUE self)
511
+ {
512
+ VALUE result;
513
+ RGeo_GeometryData* self_data;
514
+ const GEOSGeometry* self_geom;
515
+ double area;
516
+
517
+ result = Qnil;
518
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
519
+ self_geom = self_data->geom;
520
+ if (self_geom) {
521
+ if (GEOSArea_r(self_data->geos_context, self_geom, &area)) {
522
+ result = rb_float_new(area);
523
+ }
524
+ }
525
+ return result;
526
+ }
527
+
528
+
529
+ static VALUE method_multi_polygon_centroid(VALUE self)
530
+ {
531
+ VALUE result;
532
+ RGeo_GeometryData* self_data;
533
+ const GEOSGeometry* self_geom;
534
+
535
+ result = Qnil;
536
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
537
+ self_geom = self_data->geom;
538
+ if (self_geom) {
539
+ result = rgeo_wrap_geos_geometry(self_data->factory, GEOSGetCentroid_r(self_data->geos_context, self_geom), Qnil);
540
+ }
541
+ return result;
542
+ }
543
+
544
+
545
+ static VALUE method_multi_polygon_point_on_surface(VALUE self)
546
+ {
547
+ VALUE result;
548
+ RGeo_GeometryData* self_data;
549
+ const GEOSGeometry* self_geom;
550
+
551
+ result = Qnil;
552
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
553
+ self_geom = self_data->geom;
554
+ if (self_geom) {
555
+ result = rgeo_wrap_geos_geometry(self_data->factory, GEOSPointOnSurface_r(self_data->geos_context, self_geom), Qnil);
556
+ }
557
+ return result;
558
+ }
559
+
560
+
561
+ static VALUE cmethod_geometry_collection_create(VALUE module, VALUE factory, VALUE array)
562
+ {
563
+ return create_geometry_collection(module, GEOS_GEOMETRYCOLLECTION, factory, array);
564
+ }
565
+
566
+
567
+ static VALUE cmethod_multi_point_create(VALUE module, VALUE factory, VALUE array)
568
+ {
569
+ return create_geometry_collection(module, GEOS_MULTIPOINT, factory, array);
570
+ }
571
+
572
+
573
+ static VALUE cmethod_multi_line_string_create(VALUE module, VALUE factory, VALUE array)
574
+ {
575
+ return create_geometry_collection(module, GEOS_MULTILINESTRING, factory, array);
576
+ }
577
+
578
+
579
+ static VALUE cmethod_multi_polygon_create(VALUE module, VALUE factory, VALUE array)
580
+ {
581
+ return create_geometry_collection(module, GEOS_MULTIPOLYGON, factory, array);
582
+ }
583
+
584
+
585
+ /**** INITIALIZATION FUNCTION ****/
586
+
587
+
588
+ void rgeo_init_geos_geometry_collection(RGeo_Globals* globals)
589
+ {
590
+ VALUE geos_geometry_collection_methods;
591
+ VALUE geos_multi_point_methods;
592
+ VALUE geos_multi_line_string_methods;
593
+ VALUE geos_multi_polygon_methods;
594
+
595
+ // Class methods for geometry collection classes
596
+ rb_define_module_function(globals->geos_geometry_collection, "create", cmethod_geometry_collection_create, 2);
597
+ rb_define_module_function(globals->geos_multi_point, "create", cmethod_multi_point_create, 2);
598
+ rb_define_module_function(globals->geos_multi_line_string, "create", cmethod_multi_line_string_create, 2);
599
+ rb_define_module_function(globals->geos_multi_polygon, "create", cmethod_multi_polygon_create, 2);
600
+
601
+ // Methods for GeometryCollectionImpl
602
+ geos_geometry_collection_methods = rb_define_module_under(globals->geos_module, "CAPIGeometryCollectionMethods");
603
+ rb_define_method(geos_geometry_collection_methods, "rep_equals?", method_geometry_collection_eql, 1);
604
+ rb_define_method(geos_geometry_collection_methods, "eql?", method_geometry_collection_eql, 1);
605
+ rb_define_method(geos_geometry_collection_methods, "hash", method_geometry_collection_hash, 0);
606
+ rb_define_method(geos_geometry_collection_methods, "geometry_type", method_geometry_collection_geometry_type, 0);
607
+ rb_define_method(geos_geometry_collection_methods, "num_geometries", method_geometry_collection_num_geometries, 0);
608
+ rb_define_method(geos_geometry_collection_methods, "size", method_geometry_collection_num_geometries, 0);
609
+ rb_define_method(geos_geometry_collection_methods, "geometry_n", method_geometry_collection_geometry_n, 1);
610
+ rb_define_method(geos_geometry_collection_methods, "[]", method_geometry_collection_brackets, 1);
611
+ rb_define_method(geos_geometry_collection_methods, "each", method_geometry_collection_each, 0);
612
+
613
+
614
+ // Methods for MultiPointImpl
615
+ geos_multi_point_methods = rb_define_module_under(globals->geos_module, "CAPIMultiPointMethods");
616
+ rb_define_method(geos_multi_point_methods, "geometry_type", method_multi_point_geometry_type, 0);
617
+ rb_define_method(geos_multi_point_methods, "hash", method_multi_point_hash, 0);
618
+ rb_define_method(geos_multi_point_methods, "coordinates", method_multi_point_coordinates, 0);
619
+
620
+ // Methods for MultiLineStringImpl
621
+ geos_multi_line_string_methods = rb_define_module_under(globals->geos_module, "CAPIMultiLineStringMethods");
622
+ rb_define_method(geos_multi_line_string_methods, "geometry_type", method_multi_line_string_geometry_type, 0);
623
+ rb_define_method(geos_multi_line_string_methods, "length", method_multi_line_string_length, 0);
624
+ rb_define_method(geos_multi_line_string_methods, "is_closed?", method_multi_line_string_is_closed, 0);
625
+ rb_define_method(geos_multi_line_string_methods, "hash", method_multi_line_string_hash, 0);
626
+ rb_define_method(geos_multi_line_string_methods, "coordinates", method_multi_line_string_coordinates, 0);
627
+
628
+ // Methods for MultiPolygonImpl
629
+ geos_multi_polygon_methods = rb_define_module_under(globals->geos_module, "CAPIMultiPolygonMethods");
630
+ rb_define_method(geos_multi_polygon_methods, "geometry_type", method_multi_polygon_geometry_type, 0);
631
+ rb_define_method(geos_multi_polygon_methods, "area", method_multi_polygon_area, 0);
632
+ rb_define_method(geos_multi_polygon_methods, "centroid", method_multi_polygon_centroid, 0);
633
+ rb_define_method(geos_multi_polygon_methods, "point_on_surface", method_multi_polygon_point_on_surface, 0);
634
+ rb_define_method(geos_multi_polygon_methods, "hash", method_multi_polygon_hash, 0);
635
+ rb_define_method(geos_multi_polygon_methods, "coordinates", method_multi_polygon_coordinates, 0);
636
+ }
637
+
638
+
639
+ /**** OTHER PUBLIC FUNCTIONS ****/
640
+
641
+
642
+ VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
643
+ {
644
+ VALUE result;
645
+ int len1;
646
+ int len2;
647
+ int i;
648
+ const GEOSGeometry* sub_geom1;
649
+ const GEOSGeometry* sub_geom2;
650
+ int type1;
651
+ int type2;
652
+
653
+ result = Qnil;
654
+ if (geom1 && geom2) {
655
+ len1 = GEOSGetNumGeometries_r(context, geom1);
656
+ len2 = GEOSGetNumGeometries_r(context, geom2);
657
+ if (len1 >= 0 && len2 >= 0) {
658
+ if (len1 == len2) {
659
+ result = Qtrue;
660
+ for (i=0; i<len1; ++i) {
661
+ sub_geom1 = GEOSGetGeometryN_r(context, geom1, i);
662
+ sub_geom2 = GEOSGetGeometryN_r(context, geom2, i);
663
+ if (sub_geom1 && sub_geom2) {
664
+ type1 = GEOSGeomTypeId_r(context, sub_geom1);
665
+ type2 = GEOSGeomTypeId_r(context, sub_geom2);
666
+ if (type1 >= 0 && type2 >= 0) {
667
+ if (type1 == type2) {
668
+ switch (type1) {
669
+ case GEOS_POINT:
670
+ case GEOS_LINESTRING:
671
+ case GEOS_LINEARRING:
672
+ result = rgeo_geos_coordseqs_eql(context, sub_geom1, sub_geom2, check_z);
673
+ break;
674
+ case GEOS_POLYGON:
675
+ result = rgeo_geos_polygons_eql(context, sub_geom1, sub_geom2, check_z);
676
+ break;
677
+ case GEOS_GEOMETRYCOLLECTION:
678
+ case GEOS_MULTIPOINT:
679
+ case GEOS_MULTILINESTRING:
680
+ case GEOS_MULTIPOLYGON:
681
+ result = rgeo_geos_geometry_collections_eql(context, sub_geom1, sub_geom2, check_z);
682
+ break;
683
+ default:
684
+ result = Qnil;
685
+ break;
686
+ }
687
+ if (!RTEST(result)) {
688
+ break;
689
+ }
690
+ }
691
+ else {
692
+ result = Qfalse;
693
+ break;
694
+ }
695
+ }
696
+ else {
697
+ result = Qnil;
698
+ break;
699
+ }
700
+ }
701
+ else {
702
+ result = Qnil;
703
+ break;
704
+ }
705
+ }
706
+ }
707
+ else {
708
+ result = Qfalse;
709
+ }
710
+ }
711
+ }
712
+ return result;
713
+ }
714
+
715
+
716
+ st_index_t rgeo_geos_geometry_collection_hash(GEOSContextHandle_t context, const GEOSGeometry* geom, st_index_t hash)
717
+ {
718
+ const GEOSGeometry* sub_geom;
719
+ int type;
720
+ unsigned int len;
721
+ unsigned int i;
722
+
723
+ if (geom) {
724
+ len = GEOSGetNumGeometries_r(context, geom);
725
+ for (i=0; i<len; ++i) {
726
+ sub_geom = GEOSGetGeometryN_r(context, geom, i);
727
+ if (sub_geom) {
728
+ type = GEOSGeomTypeId_r(context, sub_geom);
729
+ if (type >= 0) {
730
+ hash = hash ^ type;
731
+ switch (type) {
732
+ case GEOS_POINT:
733
+ case GEOS_LINESTRING:
734
+ case GEOS_LINEARRING:
735
+ hash = rgeo_geos_coordseq_hash(context, sub_geom, hash);
736
+ break;
737
+ case GEOS_POLYGON:
738
+ hash = rgeo_geos_polygon_hash(context, sub_geom, hash);
739
+ break;
740
+ case GEOS_GEOMETRYCOLLECTION:
741
+ case GEOS_MULTIPOINT:
742
+ case GEOS_MULTILINESTRING:
743
+ case GEOS_MULTIPOLYGON:
744
+ hash = rgeo_geos_geometry_collection_hash(context, sub_geom, hash);
745
+ break;
746
+ }
747
+ }
748
+ }
749
+ }
750
+ }
751
+ return hash;
752
+ }
753
+
754
+
755
+ RGEO_END_C
756
+
757
+ #endif