rgeo 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a348afadf3324ae7b79d3af50fc3574f02612e13
4
- data.tar.gz: b1eabb80d8a0bca40f41d3243da8c7d3a5c73776
3
+ metadata.gz: caa2d9cf16debf7c8a179722c869d495231a1e60
4
+ data.tar.gz: 1997fbab92a4c9a09b5c4320b517f4490536288d
5
5
  SHA512:
6
- metadata.gz: 4306a4bfd6ef26869bbace978ab2d7ee4c220f89c4d7dc8667724ae4361c1172ab114c2f35246be68cafdbaa8fcae6988f7ed52559bc7e607e2a11c9d9fda494
7
- data.tar.gz: 41c1857a1594bb0240670e98ff9c797ae91d1c843d7c4a0f5962b67bedb93108b33d809771bd980feaeb297caeb95d5058a4332fe12ef6531fa539a30871987f
6
+ metadata.gz: 3efb5ad117346bfef57e0c28d22178832a63af8a108ceeed4a852d5f48c19b0bab02ea3a446e530d336abc683e6ce9aa5a399377b41db02a57cc9f07b2e322e0
7
+ data.tar.gz: 645c51c63379aca330510b0249b9ae4ef6eb1ca057645a7eb42f81726f1b7bb6b104f2b78d3a1778bee816213016079790ba3867ace145a9c0f309e7d4bff8f5
@@ -0,0 +1,65 @@
1
+ #include <ruby.h>
2
+ #include <geos_c.h>
3
+
4
+
5
+ VALUE extract_points_from_coordinate_sequence(GEOSContextHandle_t context, const GEOSCoordSequence* coord_sequence, int zCoordinate)
6
+ {
7
+ VALUE result = Qnil;
8
+ VALUE point;
9
+ unsigned int count;
10
+ unsigned int i;
11
+ double val;
12
+
13
+ if(GEOSCoordSeq_getSize_r(context, coord_sequence, &count)) {
14
+ result = rb_ary_new2(count);
15
+ for(i = 0; i < count; ++i) {
16
+ if(zCoordinate) {
17
+ point = rb_ary_new2(3);
18
+ } else {
19
+ point = rb_ary_new2(2);
20
+ }
21
+ GEOSCoordSeq_getX_r(context, coord_sequence, i, &val);
22
+ rb_ary_push(point, rb_float_new(val));
23
+ GEOSCoordSeq_getY_r(context, coord_sequence, i, &val);
24
+ rb_ary_push(point, rb_float_new(val));
25
+ if(zCoordinate) {
26
+ GEOSCoordSeq_getZ_r(context, coord_sequence, i, &val);
27
+ rb_ary_push(point, rb_float_new(val));
28
+ }
29
+ rb_ary_push(result, point);
30
+ }
31
+ }
32
+
33
+ return result;
34
+ }
35
+
36
+ VALUE extract_points_from_polygon(GEOSContextHandle_t context, const GEOSGeometry* polygon, int zCoordinate)
37
+ {
38
+ VALUE result = Qnil;
39
+
40
+ const GEOSGeometry* ring;
41
+ const GEOSCoordSequence* coord_sequence;
42
+ unsigned int interior_ring_count;
43
+ unsigned int i;
44
+
45
+ if (polygon) {
46
+ ring = GEOSGetExteriorRing_r(context, polygon);
47
+ coord_sequence = GEOSGeom_getCoordSeq_r(context, ring);
48
+
49
+ if(coord_sequence) {
50
+ interior_ring_count = GEOSGetNumInteriorRings_r(context, polygon);
51
+ result = rb_ary_new2(interior_ring_count + 1); // exterior + inner rings
52
+
53
+ rb_ary_push(result, extract_points_from_coordinate_sequence(context, coord_sequence, zCoordinate));
54
+
55
+ for(i = 0; i < interior_ring_count; ++i) {
56
+ ring = GEOSGetInteriorRingN_r(context, polygon, i);
57
+ coord_sequence = GEOSGeom_getCoordSeq_r(context, ring);
58
+ if(coord_sequence) {
59
+ rb_ary_push(result, extract_points_from_coordinate_sequence(context, coord_sequence, zCoordinate));
60
+ }
61
+ }
62
+ }
63
+ }
64
+ return result;
65
+ }
@@ -0,0 +1,2 @@
1
+ VALUE extract_points_from_coordinate_sequence(GEOSContextHandle_t context, const GEOSCoordSequence* coord_sequence, int zCoordinate);
2
+ VALUE extract_points_from_polygon(GEOSContextHandle_t context, const GEOSGeometry* polygon, int zCoordinate);
@@ -0,0 +1,995 @@
1
+ /*
2
+ Factory and utility functions 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 "point.h"
16
+ #include "line_string.h"
17
+ #include "polygon.h"
18
+ #include "geometry_collection.h"
19
+
20
+ RGEO_BEGIN_C
21
+
22
+
23
+ /**** RUBY AND GEOS CALLBACKS ****/
24
+
25
+
26
+ // NOP message handler. GEOS requires that a message handler be set
27
+ // for every context handle.
28
+
29
+ static void message_handler(const char* fmt, ...)
30
+ {
31
+ }
32
+
33
+
34
+ // Destroy function for factory data. We destroy any serialization
35
+ // objects that have been created for the factory, and then destroy
36
+ // the GEOS context, before freeing the factory data itself.
37
+
38
+ static void destroy_factory_func(RGeo_FactoryData* data)
39
+ {
40
+ GEOSContextHandle_t context;
41
+
42
+ context = data->geos_context;
43
+ if (data->wkt_reader) {
44
+ GEOSWKTReader_destroy_r(context, data->wkt_reader);
45
+ }
46
+ if (data->wkb_reader) {
47
+ GEOSWKBReader_destroy_r(context, data->wkb_reader);
48
+ }
49
+ if (data->wkt_writer) {
50
+ GEOSWKTWriter_destroy_r(context, data->wkt_writer);
51
+ }
52
+ if (data->wkb_writer) {
53
+ GEOSWKBWriter_destroy_r(context, data->wkb_writer);
54
+ }
55
+ if (data->psych_wkt_reader) {
56
+ GEOSWKTReader_destroy_r(context, data->psych_wkt_reader);
57
+ }
58
+ if (data->marshal_wkb_reader) {
59
+ GEOSWKBReader_destroy_r(context, data->marshal_wkb_reader);
60
+ }
61
+ if (data->psych_wkt_writer) {
62
+ GEOSWKTWriter_destroy_r(context, data->psych_wkt_writer);
63
+ }
64
+ if (data->marshal_wkb_writer) {
65
+ GEOSWKBWriter_destroy_r(context, data->marshal_wkb_writer);
66
+ }
67
+ finishGEOS_r(context);
68
+ free(data);
69
+ }
70
+
71
+
72
+ // Destroy function for geometry data. We destroy the internal
73
+ // GEOS geometry (if present) before freeing the data itself.
74
+
75
+ static void destroy_geometry_func(RGeo_GeometryData* data)
76
+ {
77
+ const GEOSPreparedGeometry* prep;
78
+
79
+ if (data->geom) {
80
+ GEOSGeom_destroy_r(data->geos_context, data->geom);
81
+ }
82
+ prep = data->prep;
83
+ if (prep && prep != (const GEOSPreparedGeometry*)1 && prep != (const GEOSPreparedGeometry*)2 &&
84
+ prep != (const GEOSPreparedGeometry*)3)
85
+ {
86
+ GEOSPreparedGeom_destroy_r(data->geos_context, prep);
87
+ }
88
+ free(data);
89
+ }
90
+
91
+
92
+ // Mark function for factory data. This marks the wkt and wkb generator
93
+ // handles so they don't get collected.
94
+
95
+ static void mark_factory_func(RGeo_FactoryData* data)
96
+ {
97
+ if (!NIL_P(data->wkrep_wkt_generator)) {
98
+ rb_gc_mark(data->wkrep_wkt_generator);
99
+ }
100
+ if (!NIL_P(data->wkrep_wkb_generator)) {
101
+ rb_gc_mark(data->wkrep_wkb_generator);
102
+ }
103
+ if (!NIL_P(data->wkrep_wkt_parser)) {
104
+ rb_gc_mark(data->wkrep_wkt_parser);
105
+ }
106
+ if (!NIL_P(data->wkrep_wkb_parser)) {
107
+ rb_gc_mark(data->wkrep_wkb_parser);
108
+ }
109
+ if (!NIL_P(data->proj4_obj)) {
110
+ rb_gc_mark(data->proj4_obj);
111
+ }
112
+ if (!NIL_P(data->coord_sys_obj)) {
113
+ rb_gc_mark(data->coord_sys_obj);
114
+ }
115
+ }
116
+
117
+
118
+ // Mark function for geometry data. This marks the factory and klasses
119
+ // held by the geometry so those don't get collected.
120
+
121
+ static void mark_geometry_func(RGeo_GeometryData* data)
122
+ {
123
+ if (!NIL_P(data->factory)) {
124
+ rb_gc_mark(data->factory);
125
+ }
126
+ if (!NIL_P(data->klasses)) {
127
+ rb_gc_mark(data->klasses);
128
+ }
129
+ }
130
+
131
+
132
+ // Destroy function for globals data. We don't need to destroy any
133
+ // auxiliary data for now...
134
+
135
+ static void destroy_globals_func(RGeo_Globals* data)
136
+ {
137
+ free(data);
138
+ }
139
+
140
+
141
+ // Mark function for globals data. This should mark any globals that
142
+ // need to be held through garbage collection (none at the moment.)
143
+
144
+ static void mark_globals_func(RGeo_Globals* data)
145
+ {
146
+ }
147
+
148
+
149
+ /**** RUBY METHOD DEFINITIONS ****/
150
+
151
+
152
+ static VALUE method_factory_srid(VALUE self)
153
+ {
154
+ return INT2NUM(RGEO_FACTORY_DATA_PTR(self)->srid);
155
+ }
156
+
157
+
158
+ static VALUE method_factory_buffer_resolution(VALUE self)
159
+ {
160
+ return INT2NUM(RGEO_FACTORY_DATA_PTR(self)->buffer_resolution);
161
+ }
162
+
163
+
164
+ static VALUE method_factory_flags(VALUE self)
165
+ {
166
+ return INT2NUM(RGEO_FACTORY_DATA_PTR(self)->flags);
167
+ }
168
+
169
+
170
+ static VALUE method_factory_parse_wkt(VALUE self, VALUE str)
171
+ {
172
+ RGeo_FactoryData* self_data;
173
+ GEOSContextHandle_t self_context;
174
+ GEOSWKTReader* wkt_reader;
175
+ VALUE result;
176
+ GEOSGeometry* geom;
177
+
178
+ Check_Type(str, T_STRING);
179
+ self_data = RGEO_FACTORY_DATA_PTR(self);
180
+ self_context = self_data->geos_context;
181
+ wkt_reader = self_data->wkt_reader;
182
+ if (!wkt_reader) {
183
+ wkt_reader = GEOSWKTReader_create_r(self_context);
184
+ self_data->wkt_reader = wkt_reader;
185
+ }
186
+ result = Qnil;
187
+ if (wkt_reader) {
188
+ geom = GEOSWKTReader_read_r(self_context, wkt_reader, RSTRING_PTR(str));
189
+ if (geom) {
190
+ result = rgeo_wrap_geos_geometry(self, geom, Qnil);
191
+ }
192
+ }
193
+ return result;
194
+ }
195
+
196
+
197
+ static VALUE method_factory_parse_wkb(VALUE self, VALUE str)
198
+ {
199
+ RGeo_FactoryData* self_data;
200
+ GEOSContextHandle_t self_context;
201
+ GEOSWKBReader* wkb_reader;
202
+ VALUE result;
203
+ GEOSGeometry* geom;
204
+
205
+ Check_Type(str, T_STRING);
206
+ self_data = RGEO_FACTORY_DATA_PTR(self);
207
+ self_context = self_data->geos_context;
208
+ wkb_reader = self_data->wkb_reader;
209
+ if (!wkb_reader) {
210
+ wkb_reader = GEOSWKBReader_create_r(self_context);
211
+ self_data->wkb_reader = wkb_reader;
212
+ }
213
+ result = Qnil;
214
+ if (wkb_reader) {
215
+ geom = GEOSWKBReader_read_r(self_context, wkb_reader, (unsigned char*)RSTRING_PTR(str), (size_t)RSTRING_LEN(str));
216
+ if (geom) {
217
+ result = rgeo_wrap_geos_geometry(self, geom, Qnil);
218
+ }
219
+ }
220
+ return result;
221
+ }
222
+
223
+
224
+ static VALUE method_factory_read_for_marshal(VALUE self, VALUE str)
225
+ {
226
+ RGeo_FactoryData* self_data;
227
+ GEOSContextHandle_t self_context;
228
+ GEOSWKBReader* wkb_reader;
229
+ VALUE result;
230
+ GEOSGeometry* geom;
231
+
232
+ Check_Type(str, T_STRING);
233
+ self_data = RGEO_FACTORY_DATA_PTR(self);
234
+ self_context = self_data->geos_context;
235
+ wkb_reader = self_data->marshal_wkb_reader;
236
+ if (!wkb_reader) {
237
+ wkb_reader = GEOSWKBReader_create_r(self_context);
238
+ self_data->marshal_wkb_reader = wkb_reader;
239
+ }
240
+ result = Qnil;
241
+ if (wkb_reader) {
242
+ geom = GEOSWKBReader_read_r(self_context, wkb_reader, (unsigned char*)RSTRING_PTR(str), (size_t)RSTRING_LEN(str));
243
+ if (geom) {
244
+ result = rgeo_wrap_geos_geometry(self, geom, Qnil);
245
+ }
246
+ }
247
+ return result;
248
+ }
249
+
250
+
251
+ static VALUE method_factory_read_for_psych(VALUE self, VALUE str)
252
+ {
253
+ RGeo_FactoryData* self_data;
254
+ GEOSContextHandle_t self_context;
255
+ GEOSWKTReader* wkt_reader;
256
+ VALUE result;
257
+ GEOSGeometry* geom;
258
+
259
+ Check_Type(str, T_STRING);
260
+ self_data = RGEO_FACTORY_DATA_PTR(self);
261
+ self_context = self_data->geos_context;
262
+ wkt_reader = self_data->psych_wkt_reader;
263
+ if (!wkt_reader) {
264
+ wkt_reader = GEOSWKTReader_create_r(self_context);
265
+ self_data->psych_wkt_reader = wkt_reader;
266
+ }
267
+ result = Qnil;
268
+ if (wkt_reader) {
269
+ geom = GEOSWKTReader_read_r(self_context, wkt_reader, RSTRING_PTR(str));
270
+ if (geom) {
271
+ result = rgeo_wrap_geos_geometry(self, geom, Qnil);
272
+ }
273
+ }
274
+ return result;
275
+ }
276
+
277
+
278
+ static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
279
+ {
280
+ RGeo_FactoryData* self_data;
281
+ GEOSContextHandle_t self_context;
282
+ GEOSWKBWriter* wkb_writer;
283
+ const GEOSGeometry* geom;
284
+ VALUE result;
285
+ char* str;
286
+ size_t size;
287
+ char has_3d;
288
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
289
+ RGeo_Globals* globals;
290
+ VALUE wkb_generator;
291
+ #endif
292
+
293
+ self_data = RGEO_FACTORY_DATA_PTR(self);
294
+ self_context = self_data->geos_context;
295
+ has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
296
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
297
+ if (has_3d) {
298
+ globals = self_data->globals;
299
+ wkb_generator = globals->marshal_wkb_generator;
300
+ if (NIL_P(wkb_generator)) {
301
+ wkb_generator = rb_funcall(
302
+ rb_const_get_at(globals->geos_module, rb_intern("Utils")),
303
+ rb_intern("marshal_wkb_generator"), 0);
304
+ globals->marshal_wkb_generator = wkb_generator;
305
+ }
306
+ return rb_funcall(wkb_generator, globals->id_generate, 1, obj);
307
+ }
308
+ #endif
309
+ wkb_writer = self_data->marshal_wkb_writer;
310
+ if (!wkb_writer) {
311
+ wkb_writer = GEOSWKBWriter_create_r(self_context);
312
+ if (has_3d) {
313
+ GEOSWKBWriter_setOutputDimension_r(self_context, wkb_writer, 3);
314
+ }
315
+ self_data->marshal_wkb_writer = wkb_writer;
316
+ }
317
+ result = Qnil;
318
+ if (wkb_writer) {
319
+ geom = rgeo_get_geos_geometry_safe(obj);
320
+ if (geom) {
321
+ str = (char*)GEOSWKBWriter_write_r(self_context, wkb_writer, geom, &size);
322
+ if (str) {
323
+ result = rb_str_new(str, size);
324
+ GEOSFree_r(self_context, str);
325
+ }
326
+ }
327
+ }
328
+ return result;
329
+ }
330
+
331
+
332
+ static VALUE method_factory_write_for_psych(VALUE self, VALUE obj)
333
+ {
334
+ RGeo_FactoryData* self_data;
335
+ GEOSContextHandle_t self_context;
336
+ GEOSWKTWriter* wkt_writer;
337
+ const GEOSGeometry* geom;
338
+ VALUE result;
339
+ char* str;
340
+ size_t size;
341
+ char has_3d;
342
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
343
+ RGeo_Globals* globals;
344
+ VALUE wkt_generator;
345
+ #endif
346
+
347
+ self_data = RGEO_FACTORY_DATA_PTR(self);
348
+ self_context = self_data->geos_context;
349
+ has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
350
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
351
+ if (has_3d) {
352
+ globals = self_data->globals;
353
+ wkt_generator = globals->psych_wkt_generator;
354
+ if (NIL_P(wkt_generator)) {
355
+ wkt_generator = rb_funcall(
356
+ rb_const_get_at(globals->geos_module, rb_intern("Utils")),
357
+ rb_intern("psych_wkt_generator"), 0);
358
+ globals->psych_wkt_generator = wkt_generator;
359
+ }
360
+ return rb_funcall(wkt_generator, globals->id_generate, 1, obj);
361
+ }
362
+ #endif
363
+ wkt_writer = self_data->psych_wkt_writer;
364
+ if (!wkt_writer) {
365
+ wkt_writer = GEOSWKTWriter_create_r(self_context);
366
+ if (has_3d) {
367
+ GEOSWKTWriter_setOutputDimension_r(self_context, wkt_writer, 3);
368
+ }
369
+ self_data->psych_wkt_writer = wkt_writer;
370
+ }
371
+ result = Qnil;
372
+ if (wkt_writer) {
373
+ geom = rgeo_get_geos_geometry_safe(obj);
374
+ if (geom) {
375
+ str = GEOSWKTWriter_write_r(self_context, wkt_writer, geom);
376
+ if (str) {
377
+ result = rb_str_new2(str);
378
+ GEOSFree_r(self_context, str);
379
+ }
380
+ }
381
+ }
382
+ return result;
383
+ }
384
+
385
+
386
+ static VALUE cmethod_factory_geos_version(VALUE klass)
387
+ {
388
+ return rb_str_new2(GEOS_VERSION);
389
+ }
390
+
391
+
392
+ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE buffer_resolution,
393
+ VALUE wkt_generator, VALUE wkb_generator, VALUE proj4_obj, VALUE coord_sys_obj)
394
+ {
395
+ VALUE result;
396
+ RGeo_FactoryData* data;
397
+ GEOSContextHandle_t context;
398
+ VALUE wrapped_globals;
399
+
400
+ result = Qnil;
401
+ data = ALLOC(RGeo_FactoryData);
402
+ if (data) {
403
+ context = initGEOS_r(message_handler, message_handler);
404
+ if (context) {
405
+ wrapped_globals = rb_const_get_at(klass, rb_intern("INTERNAL_CGLOBALS"));
406
+ data->globals = (RGeo_Globals*)DATA_PTR(wrapped_globals);
407
+ data->geos_context = context;
408
+ data->flags = NUM2INT(flags);
409
+ data->srid = NUM2INT(srid);
410
+ data->buffer_resolution = NUM2INT(buffer_resolution);
411
+ data->wkt_reader = NULL;
412
+ data->wkb_reader = NULL;
413
+ data->wkt_writer = NULL;
414
+ data->wkb_writer = NULL;
415
+ data->psych_wkt_reader = NULL;
416
+ data->marshal_wkb_reader = NULL;
417
+ data->psych_wkt_writer = NULL;
418
+ data->marshal_wkb_writer = NULL;
419
+ data->wkrep_wkt_generator = wkt_generator;
420
+ data->wkrep_wkb_generator = wkb_generator;
421
+ data->wkrep_wkt_parser = Qnil;
422
+ data->wkrep_wkb_parser = Qnil;
423
+ data->proj4_obj = proj4_obj;
424
+ data->coord_sys_obj = coord_sys_obj;
425
+ result = Data_Wrap_Struct(klass, mark_factory_func, destroy_factory_func, data);
426
+ }
427
+ else {
428
+ free(data);
429
+ }
430
+ }
431
+ return result;
432
+ }
433
+
434
+
435
+ static VALUE alloc_factory(VALUE klass)
436
+ {
437
+ return cmethod_factory_create(klass, INT2NUM(0), INT2NUM(0), INT2NUM(0), Qnil, Qnil, Qnil, Qnil);
438
+ }
439
+
440
+
441
+ static VALUE method_factory_initialize_copy(VALUE self, VALUE orig)
442
+ {
443
+ RGeo_FactoryData* self_data;
444
+ RGeo_FactoryData* orig_data;
445
+ GEOSContextHandle_t context;
446
+
447
+ // Clear out existing data
448
+ self_data = RGEO_FACTORY_DATA_PTR(self);
449
+ context = self_data->geos_context;
450
+ if (self_data->wkt_reader) {
451
+ GEOSWKTReader_destroy_r(context, self_data->wkt_reader);
452
+ self_data->wkt_reader = NULL;
453
+ }
454
+ if (self_data->wkb_reader) {
455
+ GEOSWKBReader_destroy_r(context, self_data->wkb_reader);
456
+ self_data->wkb_reader = NULL;
457
+ }
458
+ if (self_data->wkt_writer) {
459
+ GEOSWKTWriter_destroy_r(context, self_data->wkt_writer);
460
+ self_data->wkt_writer = NULL;
461
+ }
462
+ if (self_data->wkb_writer) {
463
+ GEOSWKBWriter_destroy_r(context, self_data->wkb_writer);
464
+ self_data->wkb_writer = NULL;
465
+ }
466
+ if (self_data->psych_wkt_reader) {
467
+ GEOSWKTReader_destroy_r(context, self_data->psych_wkt_reader);
468
+ self_data->psych_wkt_reader = NULL;
469
+ }
470
+ if (self_data->marshal_wkb_reader) {
471
+ GEOSWKBReader_destroy_r(context, self_data->marshal_wkb_reader);
472
+ self_data->marshal_wkb_reader = NULL;
473
+ }
474
+ if (self_data->psych_wkt_writer) {
475
+ GEOSWKTWriter_destroy_r(context, self_data->psych_wkt_writer);
476
+ self_data->psych_wkt_writer = NULL;
477
+ }
478
+ if (self_data->marshal_wkb_writer) {
479
+ GEOSWKBWriter_destroy_r(context, self_data->marshal_wkb_writer);
480
+ self_data->marshal_wkb_writer = NULL;
481
+ }
482
+ self_data->wkrep_wkt_generator = Qnil;
483
+ self_data->wkrep_wkb_generator = Qnil;
484
+ self_data->wkrep_wkt_parser = Qnil;
485
+ self_data->wkrep_wkb_parser = Qnil;
486
+ self_data->proj4_obj = Qnil;
487
+ self_data->coord_sys_obj = Qnil;
488
+
489
+ // Copy new data from original object
490
+ if (TYPE(orig) == T_DATA && RDATA(orig)->dfree == (RUBY_DATA_FUNC)destroy_factory_func) {
491
+ orig_data = RGEO_FACTORY_DATA_PTR(orig);
492
+ self_data->flags = orig_data->flags;
493
+ self_data->srid = orig_data->srid;
494
+ self_data->buffer_resolution = orig_data->buffer_resolution;
495
+ self_data->wkrep_wkt_generator = orig_data->wkrep_wkt_generator;
496
+ self_data->wkrep_wkb_generator = orig_data->wkrep_wkb_generator;
497
+ self_data->wkrep_wkt_parser = orig_data->wkrep_wkt_parser;
498
+ self_data->wkrep_wkb_parser = orig_data->wkrep_wkb_parser;
499
+ self_data->proj4_obj = orig_data->proj4_obj;
500
+ self_data->coord_sys_obj = orig_data->coord_sys_obj;
501
+ }
502
+ return self;
503
+ }
504
+
505
+
506
+ static VALUE method_set_wkrep_parsers(VALUE self, VALUE wkt_parser, VALUE wkb_parser)
507
+ {
508
+ RGeo_FactoryData* self_data;
509
+
510
+ self_data = RGEO_FACTORY_DATA_PTR(self);
511
+ self_data->wkrep_wkt_parser = wkt_parser;
512
+ self_data->wkrep_wkb_parser = wkb_parser;
513
+
514
+ return self;
515
+ }
516
+
517
+
518
+ static VALUE method_get_proj4(VALUE self)
519
+ {
520
+ return RGEO_FACTORY_DATA_PTR(self)->proj4_obj;
521
+ }
522
+
523
+
524
+ static VALUE method_get_coord_sys(VALUE self)
525
+ {
526
+ return RGEO_FACTORY_DATA_PTR(self)->coord_sys_obj;
527
+ }
528
+
529
+
530
+ static VALUE method_get_wkt_generator(VALUE self)
531
+ {
532
+ return RGEO_FACTORY_DATA_PTR(self)->wkrep_wkt_generator;
533
+ }
534
+
535
+
536
+ static VALUE method_get_wkb_generator(VALUE self)
537
+ {
538
+ return RGEO_FACTORY_DATA_PTR(self)->wkrep_wkb_generator;
539
+ }
540
+
541
+
542
+ static VALUE method_get_wkt_parser(VALUE self)
543
+ {
544
+ return RGEO_FACTORY_DATA_PTR(self)->wkrep_wkt_parser;
545
+ }
546
+
547
+
548
+ static VALUE method_get_wkb_parser(VALUE self)
549
+ {
550
+ return RGEO_FACTORY_DATA_PTR(self)->wkrep_wkb_parser;
551
+ }
552
+
553
+
554
+ static VALUE alloc_geometry(VALUE klass)
555
+ {
556
+ return rgeo_wrap_geos_geometry(Qnil, NULL, klass);
557
+ }
558
+
559
+
560
+ /**** INITIALIZATION FUNCTION ****/
561
+
562
+
563
+ RGeo_Globals* rgeo_init_geos_factory()
564
+ {
565
+ RGeo_Globals* globals;
566
+ VALUE rgeo_module;
567
+ VALUE geos_factory_class;
568
+ VALUE wrapped_globals;
569
+ VALUE feature_module;
570
+
571
+ globals = ALLOC(RGeo_Globals);
572
+
573
+ // Cache some modules so we don't have to look them up by name every time
574
+ rgeo_module = rb_define_module("RGeo");
575
+ feature_module = rb_define_module_under(rgeo_module, "Feature");
576
+ globals->feature_module = feature_module;
577
+ globals->geos_module = rb_define_module_under(rgeo_module, "Geos");
578
+ globals->feature_geometry = rb_const_get_at(feature_module, rb_intern("Geometry"));
579
+ globals->feature_point = rb_const_get_at(feature_module, rb_intern("Point"));
580
+ globals->feature_line_string = rb_const_get_at(feature_module, rb_intern("LineString"));
581
+ globals->feature_linear_ring = rb_const_get_at(feature_module, rb_intern("LinearRing"));
582
+ globals->feature_line = rb_const_get_at(feature_module, rb_intern("Line"));
583
+ globals->feature_polygon = rb_const_get_at(feature_module, rb_intern("Polygon"));
584
+ globals->feature_geometry_collection = rb_const_get_at(feature_module, rb_intern("GeometryCollection"));
585
+ globals->feature_multi_point = rb_const_get_at(feature_module, rb_intern("MultiPoint"));
586
+ globals->feature_multi_line_string = rb_const_get_at(feature_module, rb_intern("MultiLineString"));
587
+ globals->feature_multi_polygon = rb_const_get_at(feature_module, rb_intern("MultiPolygon"));
588
+
589
+ // Cache some commonly used names
590
+ globals->id_cast = rb_intern("cast");
591
+ globals->id_eql = rb_intern("eql?");
592
+ globals->id_generate = rb_intern("generate");
593
+ globals->id_enum_for = rb_intern("enum_for");
594
+ globals->id_hash = rb_intern("hash");
595
+ globals->sym_force_new = ID2SYM(rb_intern("force_new"));
596
+ globals->sym_keep_subtype = ID2SYM(rb_intern("keep_subtype"));
597
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
598
+ globals->psych_wkt_generator = Qnil;
599
+ globals->marshal_wkb_generator = Qnil;
600
+ #endif
601
+
602
+ // Add C methods to the factory.
603
+ geos_factory_class = rb_define_class_under(globals->geos_module, "CAPIFactory", rb_cObject);
604
+ rb_define_alloc_func(geos_factory_class, alloc_factory);
605
+ rb_define_method(geos_factory_class, "initialize_copy", method_factory_initialize_copy, 1);
606
+ rb_define_method(geos_factory_class, "_parse_wkt_impl", method_factory_parse_wkt, 1);
607
+ rb_define_method(geos_factory_class, "_parse_wkb_impl", method_factory_parse_wkb, 1);
608
+ rb_define_method(geos_factory_class, "_srid", method_factory_srid, 0);
609
+ rb_define_method(geos_factory_class, "_buffer_resolution", method_factory_buffer_resolution, 0);
610
+ rb_define_method(geos_factory_class, "_flags", method_factory_flags, 0);
611
+ rb_define_method(geos_factory_class, "_set_wkrep_parsers", method_set_wkrep_parsers, 2);
612
+ rb_define_method(geos_factory_class, "_proj4", method_get_proj4, 0);
613
+ rb_define_method(geos_factory_class, "_coord_sys", method_get_coord_sys, 0);
614
+ rb_define_method(geos_factory_class, "_wkt_generator", method_get_wkt_generator, 0);
615
+ rb_define_method(geos_factory_class, "_wkb_generator", method_get_wkb_generator, 0);
616
+ rb_define_method(geos_factory_class, "_wkt_parser", method_get_wkt_parser, 0);
617
+ rb_define_method(geos_factory_class, "_wkb_parser", method_get_wkb_parser, 0);
618
+ rb_define_method(geos_factory_class, "_read_for_marshal", method_factory_read_for_marshal, 1);
619
+ rb_define_method(geos_factory_class, "_write_for_marshal", method_factory_write_for_marshal, 1);
620
+ rb_define_method(geos_factory_class, "_read_for_psych", method_factory_read_for_psych, 1);
621
+ rb_define_method(geos_factory_class, "_write_for_psych", method_factory_write_for_psych, 1);
622
+ rb_define_module_function(geos_factory_class, "_create", cmethod_factory_create, 7);
623
+ rb_define_module_function(geos_factory_class, "_geos_version", cmethod_factory_geos_version, 0);
624
+
625
+ // Pre-define implementation classes and set up allocation methods
626
+ globals->geos_geometry = rb_define_class_under(globals->geos_module, "CAPIGeometryImpl", rb_cObject);
627
+ rb_define_alloc_func(globals->geos_geometry, alloc_geometry);
628
+ globals->geos_point = rb_define_class_under(globals->geos_module, "CAPIPointImpl", rb_cObject);
629
+ rb_define_alloc_func(globals->geos_point, alloc_geometry);
630
+ globals->geos_line_string = rb_define_class_under(globals->geos_module, "CAPILineStringImpl", rb_cObject);
631
+ rb_define_alloc_func(globals->geos_line_string, alloc_geometry);
632
+ globals->geos_linear_ring = rb_define_class_under(globals->geos_module, "CAPILinearRingImpl", rb_cObject);
633
+ rb_define_alloc_func(globals->geos_linear_ring, alloc_geometry);
634
+ globals->geos_line = rb_define_class_under(globals->geos_module, "CAPILineImpl", rb_cObject);
635
+ rb_define_alloc_func(globals->geos_line, alloc_geometry);
636
+ globals->geos_polygon = rb_define_class_under(globals->geos_module, "CAPIPolygonImpl", rb_cObject);
637
+ rb_define_alloc_func(globals->geos_polygon, alloc_geometry);
638
+ globals->geos_geometry_collection = rb_define_class_under(globals->geos_module, "CAPIGeometryCollectionImpl", rb_cObject);
639
+ rb_define_alloc_func(globals->geos_geometry_collection, alloc_geometry);
640
+ globals->geos_multi_point = rb_define_class_under(globals->geos_module, "CAPIMultiPointImpl", rb_cObject);
641
+ rb_define_alloc_func(globals->geos_multi_point, alloc_geometry);
642
+ globals->geos_multi_line_string = rb_define_class_under(globals->geos_module, "CAPIMultiLineStringImpl", rb_cObject);
643
+ rb_define_alloc_func(globals->geos_multi_line_string, alloc_geometry);
644
+ globals->geos_multi_polygon = rb_define_class_under(globals->geos_module, "CAPIMultiPolygonImpl", rb_cObject);
645
+ rb_define_alloc_func(globals->geos_multi_polygon, alloc_geometry);
646
+
647
+ // Wrap the globals in a Ruby object and store it off so we have access
648
+ // to it later. Each factory instance will reference it internally.
649
+ wrapped_globals = Data_Wrap_Struct(rb_cObject, mark_globals_func, destroy_globals_func, globals);
650
+ rb_define_const(geos_factory_class, "INTERNAL_CGLOBALS", wrapped_globals);
651
+
652
+ return globals;
653
+ }
654
+
655
+
656
+ /**** OTHER PUBLIC FUNCTIONS ****/
657
+
658
+
659
+ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
660
+ {
661
+ VALUE result;
662
+ RGeo_FactoryData* factory_data;
663
+ GEOSContextHandle_t factory_context;
664
+ VALUE klasses;
665
+ RGeo_Globals* globals;
666
+ VALUE inferred_klass;
667
+ char is_collection;
668
+ RGeo_GeometryData* data;
669
+
670
+ result = Qnil;
671
+ if (geom || !NIL_P(klass)) {
672
+ factory_data = NIL_P(factory) ? NULL : RGEO_FACTORY_DATA_PTR(factory);
673
+ factory_context = factory_data ? factory_data->geos_context : NULL;
674
+ globals = factory_data ? factory_data->globals : NULL;
675
+
676
+ // We don't allow "empty" points, so replace such objects with
677
+ // an empty collection.
678
+ if (geom && factory) {
679
+ if (GEOSGeomTypeId_r(factory_context, geom) == GEOS_POINT && GEOSGetNumCoordinates_r(factory_context, geom) == 0) {
680
+ GEOSGeom_destroy_r(factory_context, geom);
681
+ geom = GEOSGeom_createCollection_r(factory_context, GEOS_GEOMETRYCOLLECTION, NULL, 0);
682
+ klass = globals->geos_geometry_collection;
683
+ }
684
+ }
685
+
686
+ klasses = Qnil;
687
+ if (TYPE(klass) != T_CLASS) {
688
+ inferred_klass = Qnil;
689
+ is_collection = 0;
690
+ switch (GEOSGeomTypeId_r(factory_context, geom)) {
691
+ case GEOS_POINT:
692
+ inferred_klass = globals->geos_point;
693
+ break;
694
+ case GEOS_LINESTRING:
695
+ inferred_klass = globals->geos_line_string;
696
+ break;
697
+ case GEOS_LINEARRING:
698
+ inferred_klass = globals->geos_linear_ring;
699
+ break;
700
+ case GEOS_POLYGON:
701
+ inferred_klass = globals->geos_polygon;
702
+ break;
703
+ case GEOS_MULTIPOINT:
704
+ inferred_klass = globals->geos_multi_point;
705
+ is_collection = 1;
706
+ break;
707
+ case GEOS_MULTILINESTRING:
708
+ inferred_klass = globals->geos_multi_line_string;
709
+ is_collection = 1;
710
+ break;
711
+ case GEOS_MULTIPOLYGON:
712
+ inferred_klass = globals->geos_multi_polygon;
713
+ is_collection = 1;
714
+ break;
715
+ case GEOS_GEOMETRYCOLLECTION:
716
+ inferred_klass = globals->geos_geometry_collection;
717
+ is_collection = 1;
718
+ break;
719
+ default:
720
+ inferred_klass = globals->geos_geometry;
721
+ break;
722
+ }
723
+ if (TYPE(klass) == T_ARRAY && is_collection) {
724
+ klasses = klass;
725
+ }
726
+ klass = inferred_klass;
727
+ }
728
+ data = ALLOC(RGeo_GeometryData);
729
+ if (data) {
730
+ if (geom) {
731
+ GEOSSetSRID_r(factory_context, geom, factory_data->srid);
732
+ }
733
+ data->geos_context = factory_context;
734
+ data->geom = geom;
735
+ data->prep = factory_data && ((factory_data->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC) != 0) ?
736
+ (GEOSPreparedGeometry*)1 : NULL;
737
+ data->factory = factory;
738
+ data->klasses = klasses;
739
+ result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data);
740
+ }
741
+ }
742
+ return result;
743
+ }
744
+
745
+
746
+ VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VALUE klass)
747
+ {
748
+ VALUE result;
749
+ GEOSGeometry* clone_geom;
750
+
751
+ result = Qnil;
752
+ if (geom) {
753
+ clone_geom = GEOSGeom_clone_r(RGEO_FACTORY_DATA_PTR(factory)->geos_context, geom);
754
+ if (clone_geom) {
755
+ result = rgeo_wrap_geos_geometry(factory, clone_geom, klass);
756
+ }
757
+ }
758
+ return result;
759
+ }
760
+
761
+
762
+ const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj, VALUE type)
763
+ {
764
+ VALUE object;
765
+ const GEOSGeometry* geom;
766
+ RGeo_Globals* globals;
767
+
768
+ if (NIL_P(type) && TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func && RGEO_GEOMETRY_DATA_PTR(obj)->factory == factory) {
769
+ object = obj;
770
+ }
771
+ else {
772
+ globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
773
+ object = rb_funcall(globals->feature_module, globals->id_cast, 3, obj, factory, type);
774
+ }
775
+ geom = NULL;
776
+ if (!NIL_P(object)) {
777
+ geom = RGEO_GEOMETRY_DATA_PTR(object)->geom;
778
+ }
779
+ return geom;
780
+ }
781
+
782
+
783
+ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, VALUE type, VALUE* klasses)
784
+ {
785
+ VALUE object;
786
+ GEOSGeometry* geom;
787
+ RGeo_GeometryData* object_data;
788
+ const GEOSPreparedGeometry* prep;
789
+ RGeo_Globals* globals;
790
+
791
+ if (klasses) {
792
+ *klasses = Qnil;
793
+ }
794
+ globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
795
+ object = rb_funcall(globals->feature_module, globals->id_cast, 5, obj, factory, type, globals->sym_force_new, globals->sym_keep_subtype);
796
+ geom = NULL;
797
+ if (!NIL_P(object)) {
798
+ object_data = RGEO_GEOMETRY_DATA_PTR(object);
799
+ geom = object_data->geom;
800
+ if (klasses) {
801
+ *klasses = object_data->klasses;
802
+ if (NIL_P(*klasses)) {
803
+ *klasses = CLASS_OF(object);
804
+ }
805
+ }
806
+ prep = object_data->prep;
807
+ if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
808
+ GEOSPreparedGeom_destroy_r(object_data->geos_context, prep);
809
+ }
810
+ object_data->geos_context = NULL;
811
+ object_data->geom = NULL;
812
+ object_data->prep = NULL;
813
+ object_data->factory = Qnil;
814
+ object_data->klasses = Qnil;
815
+ }
816
+ return geom;
817
+ }
818
+
819
+
820
+ char rgeo_is_geos_object(VALUE obj)
821
+ {
822
+ return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? 1 : 0;
823
+ }
824
+
825
+
826
+ const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj)
827
+ {
828
+ return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? (const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(obj)->geom) : NULL;
829
+ }
830
+
831
+
832
+ VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
833
+ {
834
+ VALUE result;
835
+ const GEOSCoordSequence* cs1;
836
+ const GEOSCoordSequence* cs2;
837
+ unsigned int len1;
838
+ unsigned int len2;
839
+ unsigned int i;
840
+ double val1, val2;
841
+
842
+ result = Qnil;
843
+ if (geom1 && geom2) {
844
+ cs1 = GEOSGeom_getCoordSeq_r(context, geom1);
845
+ cs2 = GEOSGeom_getCoordSeq_r(context, geom2);
846
+ if (cs1 && cs2) {
847
+ len1 = 0;
848
+ len2 = 0;
849
+ if (GEOSCoordSeq_getSize_r(context, cs1, &len1) && GEOSCoordSeq_getSize_r(context, cs2, &len2)) {
850
+ if (len1 == len2) {
851
+ result = Qtrue;
852
+ for (i=0; i<len1; ++i) {
853
+ if (GEOSCoordSeq_getX_r(context, cs1, i, &val1) && GEOSCoordSeq_getX_r(context, cs2, i, &val2)) {
854
+ if (val1 == val2) {
855
+ if (GEOSCoordSeq_getY_r(context, cs1, i, &val1) && GEOSCoordSeq_getY_r(context, cs2, i, &val2)) {
856
+ if (val1 == val2) {
857
+ if (check_z) {
858
+ val1 = 0;
859
+ if (!GEOSCoordSeq_getZ_r(context, cs1, i, &val1)) {
860
+ result = Qnil;
861
+ break;
862
+ }
863
+ val2 = 0;
864
+ if (!GEOSCoordSeq_getZ_r(context, cs2, i, &val2)) {
865
+ result = Qnil;
866
+ break;
867
+ }
868
+ if (val1 != val2) {
869
+ result = Qfalse;
870
+ break;
871
+ }
872
+ }
873
+ }
874
+ else { // Y coords are different
875
+ result = Qfalse;
876
+ break;
877
+ }
878
+ }
879
+ else { // Failed to get Y coords
880
+ result = Qnil;
881
+ break;
882
+ }
883
+ }
884
+ else { // X coords are different
885
+ result = Qfalse;
886
+ break;
887
+ }
888
+ }
889
+ else { // Failed to get X coords
890
+ result = Qnil;
891
+ break;
892
+ }
893
+ } // Iteration over coords
894
+ }
895
+ else { // Lengths are different
896
+ result = Qfalse;
897
+ }
898
+ }
899
+ }
900
+ }
901
+ return result;
902
+ }
903
+
904
+
905
+ VALUE rgeo_geos_klasses_and_factories_eql(VALUE obj1, VALUE obj2)
906
+ {
907
+ VALUE result;
908
+ VALUE factory;
909
+
910
+ result = Qnil;
911
+ if (rb_obj_class(obj1) != rb_obj_class(obj2)) {
912
+ result = Qfalse;
913
+ }
914
+ else {
915
+ factory = RGEO_GEOMETRY_DATA_PTR(obj1)->factory;
916
+ result = rb_funcall(factory, RGEO_FACTORY_DATA_PTR(factory)->globals->id_eql, 1, RGEO_GEOMETRY_DATA_PTR(obj2)->factory);
917
+ }
918
+ return result;
919
+ }
920
+
921
+
922
+ typedef struct {
923
+ st_index_t seed_hash;
924
+ double x;
925
+ double y;
926
+ double z;
927
+ } RGeo_Coordseq_Hash_Struct;
928
+
929
+ st_index_t rgeo_geos_coordseq_hash(GEOSContextHandle_t context, const GEOSGeometry* geom, st_index_t hash)
930
+ {
931
+ const GEOSCoordSequence* cs;
932
+ unsigned int len;
933
+ unsigned int i;
934
+ RGeo_Coordseq_Hash_Struct hash_struct;
935
+
936
+ if (geom) {
937
+ cs = GEOSGeom_getCoordSeq_r(context, geom);
938
+ if (cs) {
939
+ if (GEOSCoordSeq_getSize_r(context, cs, &len)) {
940
+ for (i=0; i<len; ++i) {
941
+ if (GEOSCoordSeq_getX_r(context, cs, i, &hash_struct.x)) {
942
+ if (GEOSCoordSeq_getY_r(context, cs, i, &hash_struct.y)) {
943
+ if (!GEOSCoordSeq_getY_r(context, cs, i, &hash_struct.z)) {
944
+ hash_struct.z = 0;
945
+ }
946
+ hash_struct.seed_hash = hash;
947
+ hash = rb_memhash(&hash_struct, sizeof(RGeo_Coordseq_Hash_Struct));
948
+ }
949
+ }
950
+ }
951
+ }
952
+ }
953
+ }
954
+ return hash;
955
+ }
956
+
957
+
958
+ typedef struct {
959
+ st_index_t seed_hash;
960
+ st_index_t h1;
961
+ st_index_t h2;
962
+ } RGeo_Objbase_Hash_Struct;
963
+
964
+ st_index_t rgeo_geos_objbase_hash(VALUE factory, VALUE type_module, st_index_t hash)
965
+ {
966
+ ID hash_method;
967
+ RGeo_Objbase_Hash_Struct hash_struct;
968
+
969
+ hash_method = RGEO_FACTORY_DATA_PTR(factory)->globals->id_hash;
970
+ hash_struct.seed_hash = hash;
971
+ hash_struct.h1 = FIX2LONG(rb_funcall(factory, hash_method, 0));
972
+ hash_struct.h2 = FIX2LONG(rb_funcall(type_module, hash_method, 0));
973
+ return rb_memhash(&hash_struct, sizeof(RGeo_Objbase_Hash_Struct));
974
+ }
975
+
976
+
977
+ st_index_t rgeo_internal_memhash(const void* ptr, long len)
978
+ {
979
+ const char* bytes;
980
+ st_index_t hval;
981
+ long i;
982
+
983
+ bytes = (const char*)ptr;
984
+ hval = 0x811c9dc5;
985
+ for (i=0; i<len; ++i) {
986
+ hval ^= (unsigned int)(*bytes++);
987
+ hval *= 0x01000193;
988
+ }
989
+ return hval;
990
+ }
991
+
992
+
993
+ RGEO_END_C
994
+
995
+ #endif