rgeo 2.1.1 → 2.4.0

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +160 -0
  3. data/ext/geos_c_impl/analysis.c +80 -0
  4. data/ext/geos_c_impl/analysis.h +40 -0
  5. data/ext/geos_c_impl/errors.c +35 -0
  6. data/ext/geos_c_impl/errors.h +22 -0
  7. data/ext/geos_c_impl/extconf.rb +2 -0
  8. data/ext/geos_c_impl/factory.c +179 -174
  9. data/ext/geos_c_impl/factory.h +20 -49
  10. data/ext/geos_c_impl/geometry.c +17 -16
  11. data/ext/geos_c_impl/geometry.h +1 -3
  12. data/ext/geos_c_impl/geometry_collection.c +39 -44
  13. data/ext/geos_c_impl/geometry_collection.h +1 -3
  14. data/ext/geos_c_impl/globals.c +91 -0
  15. data/ext/geos_c_impl/globals.h +45 -0
  16. data/ext/geos_c_impl/line_string.c +27 -28
  17. data/ext/geos_c_impl/line_string.h +1 -3
  18. data/ext/geos_c_impl/main.c +14 -10
  19. data/ext/geos_c_impl/point.c +8 -7
  20. data/ext/geos_c_impl/point.h +1 -3
  21. data/ext/geos_c_impl/polygon.c +14 -14
  22. data/ext/geos_c_impl/polygon.h +1 -3
  23. data/ext/geos_c_impl/preface.h +8 -0
  24. data/lib/rgeo/cartesian/analysis.rb +22 -0
  25. data/lib/rgeo/cartesian/feature_methods.rb +6 -1
  26. data/lib/rgeo/cartesian.rb +7 -7
  27. data/lib/rgeo/coord_sys.rb +6 -6
  28. data/lib/rgeo/error.rb +4 -0
  29. data/lib/rgeo/feature/curve.rb +12 -2
  30. data/lib/rgeo/feature/geometry.rb +12 -2
  31. data/lib/rgeo/feature/linear_ring.rb +10 -0
  32. data/lib/rgeo/feature/multi_curve.rb +6 -1
  33. data/lib/rgeo/feature.rb +17 -17
  34. data/lib/rgeo/geographic/interface.rb +2 -1
  35. data/lib/rgeo/geographic/projected_feature_methods.rb +12 -2
  36. data/lib/rgeo/geographic/spherical_feature_classes.rb +1 -0
  37. data/lib/rgeo/geographic/spherical_feature_methods.rb +29 -1
  38. data/lib/rgeo/geographic.rb +10 -10
  39. data/lib/rgeo/geos/capi_factory.rb +3 -3
  40. data/lib/rgeo/geos/capi_feature_classes.rb +33 -0
  41. data/lib/rgeo/geos/ffi_feature_methods.rb +34 -5
  42. data/lib/rgeo/geos/interface.rb +18 -4
  43. data/lib/rgeo/geos/zm_feature_methods.rb +30 -5
  44. data/lib/rgeo/geos.rb +11 -11
  45. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +33 -5
  46. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +62 -8
  47. data/lib/rgeo/impl_helper/basic_point_methods.rb +12 -2
  48. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +44 -2
  49. data/lib/rgeo/impl_helper.rb +7 -7
  50. data/lib/rgeo/version.rb +1 -1
  51. data/lib/rgeo/wkrep/wkb_generator.rb +1 -1
  52. data/lib/rgeo/wkrep/wkt_generator.rb +6 -6
  53. data/lib/rgeo/wkrep.rb +4 -4
  54. data/lib/rgeo.rb +9 -9
  55. metadata +26 -14
@@ -10,12 +10,15 @@
10
10
  #include <ruby.h>
11
11
  #include <geos_c.h>
12
12
 
13
+ #include "globals.h"
14
+
13
15
  #include "factory.h"
14
16
  #include "geometry.h"
15
17
  #include "point.h"
16
18
  #include "line_string.h"
17
19
  #include "polygon.h"
18
20
  #include "geometry_collection.h"
21
+ #include "errors.h"
19
22
 
20
23
  RGEO_BEGIN_C
21
24
 
@@ -35,82 +38,89 @@ static void message_handler(const char* fmt, ...)
35
38
  // objects that have been created for the factory, and then destroy
36
39
  // the GEOS context, before freeing the factory data itself.
37
40
 
38
- static void destroy_factory_func(RGeo_FactoryData* data)
41
+ static void destroy_factory_func(void* data)
39
42
  {
43
+ RGeo_FactoryData* factory_data;
40
44
  GEOSContextHandle_t context;
41
45
 
42
- context = data->geos_context;
43
- if (data->wkt_reader) {
44
- GEOSWKTReader_destroy_r(context, data->wkt_reader);
46
+ factory_data = (RGeo_FactoryData*)data;
47
+ context = factory_data->geos_context;
48
+ if (factory_data->wkt_reader) {
49
+ GEOSWKTReader_destroy_r(context, factory_data->wkt_reader);
45
50
  }
46
- if (data->wkb_reader) {
47
- GEOSWKBReader_destroy_r(context, data->wkb_reader);
51
+ if (factory_data->wkb_reader) {
52
+ GEOSWKBReader_destroy_r(context, factory_data->wkb_reader);
48
53
  }
49
- if (data->wkt_writer) {
50
- GEOSWKTWriter_destroy_r(context, data->wkt_writer);
54
+ if (factory_data->wkt_writer) {
55
+ GEOSWKTWriter_destroy_r(context, factory_data->wkt_writer);
51
56
  }
52
- if (data->wkb_writer) {
53
- GEOSWKBWriter_destroy_r(context, data->wkb_writer);
57
+ if (factory_data->wkb_writer) {
58
+ GEOSWKBWriter_destroy_r(context, factory_data->wkb_writer);
54
59
  }
55
- if (data->psych_wkt_reader) {
56
- GEOSWKTReader_destroy_r(context, data->psych_wkt_reader);
60
+ if (factory_data->psych_wkt_reader) {
61
+ GEOSWKTReader_destroy_r(context, factory_data->psych_wkt_reader);
57
62
  }
58
- if (data->marshal_wkb_reader) {
59
- GEOSWKBReader_destroy_r(context, data->marshal_wkb_reader);
63
+ if (factory_data->marshal_wkb_reader) {
64
+ GEOSWKBReader_destroy_r(context, factory_data->marshal_wkb_reader);
60
65
  }
61
- if (data->psych_wkt_writer) {
62
- GEOSWKTWriter_destroy_r(context, data->psych_wkt_writer);
66
+ if (factory_data->psych_wkt_writer) {
67
+ GEOSWKTWriter_destroy_r(context, factory_data->psych_wkt_writer);
63
68
  }
64
- if (data->marshal_wkb_writer) {
65
- GEOSWKBWriter_destroy_r(context, data->marshal_wkb_writer);
69
+ if (factory_data->marshal_wkb_writer) {
70
+ GEOSWKBWriter_destroy_r(context, factory_data->marshal_wkb_writer);
66
71
  }
67
72
  finishGEOS_r(context);
68
- free(data);
73
+ free(factory_data);
69
74
  }
70
75
 
71
76
 
72
77
  // Destroy function for geometry data. We destroy the internal
73
78
  // GEOS geometry (if present) before freeing the data itself.
74
79
 
75
- static void destroy_geometry_func(RGeo_GeometryData* data)
80
+ static void destroy_geometry_func(void* data)
76
81
  {
82
+ RGeo_GeometryData* geometry_data;
77
83
  const GEOSPreparedGeometry* prep;
78
84
 
79
- if (data->geom) {
80
- GEOSGeom_destroy_r(data->geos_context, data->geom);
85
+ geometry_data = (RGeo_GeometryData*)data;
86
+ if (geometry_data->geom) {
87
+ GEOSGeom_destroy_r(geometry_data->geos_context, geometry_data->geom);
81
88
  }
82
- prep = data->prep;
89
+ prep = geometry_data->prep;
83
90
  if (prep && prep != (const GEOSPreparedGeometry*)1 && prep != (const GEOSPreparedGeometry*)2 &&
84
91
  prep != (const GEOSPreparedGeometry*)3)
85
92
  {
86
- GEOSPreparedGeom_destroy_r(data->geos_context, prep);
93
+ GEOSPreparedGeom_destroy_r(geometry_data->geos_context, prep);
87
94
  }
88
- free(data);
95
+ free(geometry_data);
89
96
  }
90
97
 
91
98
 
92
99
  // Mark function for factory data. This marks the wkt and wkb generator
93
100
  // handles so they don't get collected.
94
101
 
95
- static void mark_factory_func(RGeo_FactoryData* data)
102
+ static void mark_factory_func(void* data)
96
103
  {
97
- if (!NIL_P(data->wkrep_wkt_generator)) {
98
- rb_gc_mark(data->wkrep_wkt_generator);
104
+ RGeo_FactoryData* factory_data;
105
+
106
+ factory_data = (RGeo_FactoryData*)data;
107
+ if (!NIL_P(factory_data->wkrep_wkt_generator)) {
108
+ mark(factory_data->wkrep_wkt_generator);
99
109
  }
100
- if (!NIL_P(data->wkrep_wkb_generator)) {
101
- rb_gc_mark(data->wkrep_wkb_generator);
110
+ if (!NIL_P(factory_data->wkrep_wkb_generator)) {
111
+ mark(factory_data->wkrep_wkb_generator);
102
112
  }
103
- if (!NIL_P(data->wkrep_wkt_parser)) {
104
- rb_gc_mark(data->wkrep_wkt_parser);
113
+ if (!NIL_P(factory_data->wkrep_wkt_parser)) {
114
+ mark(factory_data->wkrep_wkt_parser);
105
115
  }
106
- if (!NIL_P(data->wkrep_wkb_parser)) {
107
- rb_gc_mark(data->wkrep_wkb_parser);
116
+ if (!NIL_P(factory_data->wkrep_wkb_parser)) {
117
+ mark(factory_data->wkrep_wkb_parser);
108
118
  }
109
- if (!NIL_P(data->proj4_obj)) {
110
- rb_gc_mark(data->proj4_obj);
119
+ if (!NIL_P(factory_data->proj4_obj)) {
120
+ mark(factory_data->proj4_obj);
111
121
  }
112
- if (!NIL_P(data->coord_sys_obj)) {
113
- rb_gc_mark(data->coord_sys_obj);
122
+ if (!NIL_P(factory_data->coord_sys_obj)) {
123
+ mark(factory_data->coord_sys_obj);
114
124
  }
115
125
  }
116
126
 
@@ -118,32 +128,83 @@ static void mark_factory_func(RGeo_FactoryData* data)
118
128
  // Mark function for geometry data. This marks the factory and klasses
119
129
  // held by the geometry so those don't get collected.
120
130
 
121
- static void mark_geometry_func(RGeo_GeometryData* data)
131
+ static void mark_geometry_func(void* data)
122
132
  {
123
- if (!NIL_P(data->factory)) {
124
- rb_gc_mark(data->factory);
133
+ RGeo_GeometryData* geometry_data;
134
+
135
+ geometry_data = (RGeo_GeometryData*)data;
136
+ if (!NIL_P(geometry_data->factory)) {
137
+ mark(geometry_data->factory);
125
138
  }
126
- if (!NIL_P(data->klasses)) {
127
- rb_gc_mark(data->klasses);
139
+ if (!NIL_P(geometry_data->klasses)) {
140
+ mark(geometry_data->klasses);
128
141
  }
129
142
  }
130
143
 
131
144
 
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)
145
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
146
+ static void compact_factory_func(void* data)
136
147
  {
137
- free(data);
138
- }
148
+ RGeo_FactoryData* factory_data;
139
149
 
150
+ factory_data = (RGeo_FactoryData*)data;
151
+ if (!NIL_P(factory_data->wkrep_wkt_generator)) {
152
+ factory_data->wkrep_wkt_generator = rb_gc_location(factory_data->wkrep_wkt_generator);
153
+ }
154
+ if (!NIL_P(factory_data->wkrep_wkb_generator)) {
155
+ factory_data->wkrep_wkb_generator = rb_gc_location(factory_data->wkrep_wkb_generator);
156
+ }
157
+ if (!NIL_P(factory_data->wkrep_wkt_parser)) {
158
+ factory_data->wkrep_wkt_parser = rb_gc_location(factory_data->wkrep_wkt_parser);
159
+ }
160
+ if (!NIL_P(factory_data->wkrep_wkb_parser)) {
161
+ factory_data->wkrep_wkb_parser = rb_gc_location(factory_data->wkrep_wkb_parser);
162
+ }
163
+ if (!NIL_P(factory_data->proj4_obj)) {
164
+ factory_data->proj4_obj = rb_gc_location(factory_data->proj4_obj);
165
+ }
166
+ if (!NIL_P(factory_data->coord_sys_obj)) {
167
+ factory_data->coord_sys_obj = rb_gc_location(factory_data->coord_sys_obj);
168
+ }
169
+ }
140
170
 
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
171
 
144
- static void mark_globals_func(RGeo_Globals* data)
172
+ static void compact_geometry_func(void* data)
145
173
  {
174
+ RGeo_GeometryData* geometry_data;
175
+
176
+ geometry_data = (RGeo_GeometryData*)data;
177
+ if (!NIL_P(geometry_data->factory)) {
178
+ geometry_data->factory = rb_gc_location(geometry_data->factory);
179
+ }
180
+ if (!NIL_P(geometry_data->klasses)) {
181
+ geometry_data->klasses = rb_gc_location(geometry_data->klasses);
182
+ }
146
183
  }
184
+ #endif
185
+
186
+
187
+ const rb_data_type_t rgeo_factory_type = {
188
+ .wrap_struct_name = "RGeo/Factory",
189
+ .function = {
190
+ .dmark = mark_factory_func,
191
+ .dfree = destroy_factory_func,
192
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
193
+ .dcompact = compact_factory_func,
194
+ #endif
195
+ }
196
+ };
197
+
198
+ const rb_data_type_t rgeo_geometry_type = {
199
+ .wrap_struct_name = "RGeo/Geometry",
200
+ .function = {
201
+ .dmark = mark_geometry_func,
202
+ .dfree = destroy_geometry_func,
203
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
204
+ .dcompact = compact_geometry_func,
205
+ #endif
206
+ }
207
+ };
147
208
 
148
209
 
149
210
  /**** RUBY METHOD DEFINITIONS ****/
@@ -247,7 +308,6 @@ static VALUE method_factory_read_for_marshal(VALUE self, VALUE str)
247
308
  return result;
248
309
  }
249
310
 
250
-
251
311
  static VALUE method_factory_read_for_psych(VALUE self, VALUE str)
252
312
  {
253
313
  RGeo_FactoryData* self_data;
@@ -274,6 +334,9 @@ static VALUE method_factory_read_for_psych(VALUE self, VALUE str)
274
334
  return result;
275
335
  }
276
336
 
337
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
338
+ static VALUE marshal_wkb_generator;
339
+ #endif
277
340
 
278
341
  static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
279
342
  {
@@ -285,25 +348,18 @@ static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
285
348
  char* str;
286
349
  size_t size;
287
350
  char has_3d;
288
- #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
289
- RGeo_Globals* globals;
290
- VALUE wkb_generator;
291
- #endif
292
351
 
293
352
  self_data = RGEO_FACTORY_DATA_PTR(self);
294
353
  self_context = self_data->geos_context;
295
354
  has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
296
355
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
297
356
  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")),
357
+ if (NIL_P(marshal_wkb_generator)) {
358
+ marshal_wkb_generator = rb_funcall(
359
+ rb_const_get_at(rgeo_geos_module, rb_intern("Utils")),
303
360
  rb_intern("marshal_wkb_generator"), 0);
304
- globals->marshal_wkb_generator = wkb_generator;
305
361
  }
306
- return rb_funcall(wkb_generator, globals->id_generate, 1, obj);
362
+ return rb_funcall(marshal_wkb_generator, rb_intern("generate"), 1, obj);
307
363
  }
308
364
  #endif
309
365
  wkb_writer = self_data->marshal_wkb_writer;
@@ -328,6 +384,9 @@ static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
328
384
  return result;
329
385
  }
330
386
 
387
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
388
+ static VALUE psych_wkt_generator;
389
+ #endif
331
390
 
332
391
  static VALUE method_factory_write_for_psych(VALUE self, VALUE obj)
333
392
  {
@@ -338,25 +397,18 @@ static VALUE method_factory_write_for_psych(VALUE self, VALUE obj)
338
397
  VALUE result;
339
398
  char* str;
340
399
  char has_3d;
341
- #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
342
- RGeo_Globals* globals;
343
- VALUE wkt_generator;
344
- #endif
345
400
 
346
401
  self_data = RGEO_FACTORY_DATA_PTR(self);
347
402
  self_context = self_data->geos_context;
348
403
  has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
349
404
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
350
405
  if (has_3d) {
351
- globals = self_data->globals;
352
- wkt_generator = globals->psych_wkt_generator;
353
- if (NIL_P(wkt_generator)) {
354
- wkt_generator = rb_funcall(
355
- rb_const_get_at(globals->geos_module, rb_intern("Utils")),
406
+ if (NIL_P(psych_wkt_generator)) {
407
+ psych_wkt_generator = rb_funcall(
408
+ rb_const_get_at(rgeo_geos_module, rb_intern("Utils")),
356
409
  rb_intern("psych_wkt_generator"), 0);
357
- globals->psych_wkt_generator = wkt_generator;
358
410
  }
359
- return rb_funcall(wkt_generator, globals->id_generate, 1, obj);
411
+ return rb_funcall(psych_wkt_generator, rb_intern("generate"), 1, obj);
360
412
  }
361
413
  #endif
362
414
  wkt_writer = self_data->psych_wkt_writer;
@@ -403,15 +455,12 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
403
455
  VALUE result;
404
456
  RGeo_FactoryData* data;
405
457
  GEOSContextHandle_t context;
406
- VALUE wrapped_globals;
407
458
 
408
459
  result = Qnil;
409
460
  data = ALLOC(RGeo_FactoryData);
410
461
  if (data) {
411
462
  context = initGEOS_r(message_handler, message_handler);
412
463
  if (context) {
413
- wrapped_globals = rb_const_get_at(klass, rb_intern("INTERNAL_CGLOBALS"));
414
- data->globals = (RGeo_Globals*)DATA_PTR(wrapped_globals);
415
464
  data->geos_context = context;
416
465
  data->flags = NUM2INT(flags);
417
466
  data->srid = NUM2INT(srid);
@@ -430,7 +479,7 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
430
479
  data->wkrep_wkb_parser = Qnil;
431
480
  data->proj4_obj = proj4_obj;
432
481
  data->coord_sys_obj = coord_sys_obj;
433
- result = Data_Wrap_Struct(klass, mark_factory_func, destroy_factory_func, data);
482
+ result = TypedData_Wrap_Struct(klass, &rgeo_factory_type, data);
434
483
  }
435
484
  else {
436
485
  free(data);
@@ -495,7 +544,7 @@ static VALUE method_factory_initialize_copy(VALUE self, VALUE orig)
495
544
  self_data->coord_sys_obj = Qnil;
496
545
 
497
546
  // Copy new data from original object
498
- if (TYPE(orig) == T_DATA && RDATA(orig)->dfree == (RUBY_DATA_FUNC)destroy_factory_func) {
547
+ if (RGEO_FACTORY_TYPEDDATA_P(orig)) {
499
548
  orig_data = RGEO_FACTORY_DATA_PTR(orig);
500
549
  self_data->flags = orig_data->flags;
501
550
  self_data->srid = orig_data->srid;
@@ -568,47 +617,20 @@ static VALUE alloc_geometry(VALUE klass)
568
617
  /**** INITIALIZATION FUNCTION ****/
569
618
 
570
619
 
571
- RGeo_Globals* rgeo_init_geos_factory()
620
+ void rgeo_init_geos_factory()
572
621
  {
573
- RGeo_Globals* globals;
574
- VALUE rgeo_module;
575
622
  VALUE geos_factory_class;
576
- VALUE wrapped_globals;
577
- VALUE feature_module;
578
-
579
- globals = ALLOC(RGeo_Globals);
580
-
581
- // Cache some modules so we don't have to look them up by name every time
582
- rgeo_module = rb_define_module("RGeo");
583
- feature_module = rb_define_module_under(rgeo_module, "Feature");
584
- globals->feature_module = feature_module;
585
- globals->geos_module = rb_define_module_under(rgeo_module, "Geos");
586
- globals->feature_geometry = rb_const_get_at(feature_module, rb_intern("Geometry"));
587
- globals->feature_point = rb_const_get_at(feature_module, rb_intern("Point"));
588
- globals->feature_line_string = rb_const_get_at(feature_module, rb_intern("LineString"));
589
- globals->feature_linear_ring = rb_const_get_at(feature_module, rb_intern("LinearRing"));
590
- globals->feature_line = rb_const_get_at(feature_module, rb_intern("Line"));
591
- globals->feature_polygon = rb_const_get_at(feature_module, rb_intern("Polygon"));
592
- globals->feature_geometry_collection = rb_const_get_at(feature_module, rb_intern("GeometryCollection"));
593
- globals->feature_multi_point = rb_const_get_at(feature_module, rb_intern("MultiPoint"));
594
- globals->feature_multi_line_string = rb_const_get_at(feature_module, rb_intern("MultiLineString"));
595
- globals->feature_multi_polygon = rb_const_get_at(feature_module, rb_intern("MultiPolygon"));
596
-
597
- // Cache some commonly used names
598
- globals->id_cast = rb_intern("cast");
599
- globals->id_eql = rb_intern("eql?");
600
- globals->id_generate = rb_intern("generate");
601
- globals->id_enum_for = rb_intern("enum_for");
602
- globals->id_hash = rb_intern("hash");
603
- globals->sym_force_new = ID2SYM(rb_intern("force_new"));
604
- globals->sym_keep_subtype = ID2SYM(rb_intern("keep_subtype"));
623
+
605
624
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
606
- globals->psych_wkt_generator = Qnil;
607
- globals->marshal_wkb_generator = Qnil;
625
+ /* We favor rb_gc_register_address over rb_gc_register_mark_object because the value changes at runtime */
626
+ psych_wkt_generator = Qnil;
627
+ rb_gc_register_address(&psych_wkt_generator);
628
+ marshal_wkb_generator = Qnil;
629
+ rb_gc_register_address(&marshal_wkb_generator);
608
630
  #endif
609
631
 
610
632
  // Add C methods to the factory.
611
- geos_factory_class = rb_define_class_under(globals->geos_module, "CAPIFactory", rb_cObject);
633
+ geos_factory_class = rb_define_class_under(rgeo_geos_module, "CAPIFactory", rb_cObject);
612
634
  rb_define_alloc_func(geos_factory_class, alloc_factory);
613
635
  rb_define_method(geos_factory_class, "initialize_copy", method_factory_initialize_copy, 1);
614
636
  rb_define_method(geos_factory_class, "_parse_wkt_impl", method_factory_parse_wkt, 1);
@@ -631,34 +653,17 @@ RGeo_Globals* rgeo_init_geos_factory()
631
653
  rb_define_module_function(geos_factory_class, "_geos_version", cmethod_factory_geos_version, 0);
632
654
  rb_define_module_function(geos_factory_class, "_supports_unary_union?", cmethod_factory_supports_unary_union, 0);
633
655
 
634
- // Pre-define implementation classes and set up allocation methods
635
- globals->geos_geometry = rb_define_class_under(globals->geos_module, "CAPIGeometryImpl", rb_cObject);
636
- rb_define_alloc_func(globals->geos_geometry, alloc_geometry);
637
- globals->geos_point = rb_define_class_under(globals->geos_module, "CAPIPointImpl", rb_cObject);
638
- rb_define_alloc_func(globals->geos_point, alloc_geometry);
639
- globals->geos_line_string = rb_define_class_under(globals->geos_module, "CAPILineStringImpl", rb_cObject);
640
- rb_define_alloc_func(globals->geos_line_string, alloc_geometry);
641
- globals->geos_linear_ring = rb_define_class_under(globals->geos_module, "CAPILinearRingImpl", rb_cObject);
642
- rb_define_alloc_func(globals->geos_linear_ring, alloc_geometry);
643
- globals->geos_line = rb_define_class_under(globals->geos_module, "CAPILineImpl", rb_cObject);
644
- rb_define_alloc_func(globals->geos_line, alloc_geometry);
645
- globals->geos_polygon = rb_define_class_under(globals->geos_module, "CAPIPolygonImpl", rb_cObject);
646
- rb_define_alloc_func(globals->geos_polygon, alloc_geometry);
647
- globals->geos_geometry_collection = rb_define_class_under(globals->geos_module, "CAPIGeometryCollectionImpl", rb_cObject);
648
- rb_define_alloc_func(globals->geos_geometry_collection, alloc_geometry);
649
- globals->geos_multi_point = rb_define_class_under(globals->geos_module, "CAPIMultiPointImpl", rb_cObject);
650
- rb_define_alloc_func(globals->geos_multi_point, alloc_geometry);
651
- globals->geos_multi_line_string = rb_define_class_under(globals->geos_module, "CAPIMultiLineStringImpl", rb_cObject);
652
- rb_define_alloc_func(globals->geos_multi_line_string, alloc_geometry);
653
- globals->geos_multi_polygon = rb_define_class_under(globals->geos_module, "CAPIMultiPolygonImpl", rb_cObject);
654
- rb_define_alloc_func(globals->geos_multi_polygon, alloc_geometry);
655
-
656
- // Wrap the globals in a Ruby object and store it off so we have access
657
- // to it later. Each factory instance will reference it internally.
658
- wrapped_globals = Data_Wrap_Struct(rb_cObject, mark_globals_func, destroy_globals_func, globals);
659
- rb_define_const(geos_factory_class, "INTERNAL_CGLOBALS", wrapped_globals);
660
-
661
- return globals;
656
+ // Define allocation methods for global class types
657
+ rb_define_alloc_func(rgeo_geos_geometry_class, alloc_geometry);
658
+ rb_define_alloc_func(rgeo_geos_point_class, alloc_geometry);
659
+ rb_define_alloc_func(rgeo_geos_line_string_class, alloc_geometry);
660
+ rb_define_alloc_func(rgeo_geos_linear_ring_class, alloc_geometry);
661
+ rb_define_alloc_func(rgeo_geos_line_class, alloc_geometry);
662
+ rb_define_alloc_func(rgeo_geos_polygon_class, alloc_geometry);
663
+ rb_define_alloc_func(rgeo_geos_geometry_collection_class, alloc_geometry);
664
+ rb_define_alloc_func(rgeo_geos_multi_point_class, alloc_geometry);
665
+ rb_define_alloc_func(rgeo_geos_multi_line_string_class, alloc_geometry);
666
+ rb_define_alloc_func(rgeo_geos_multi_polygon_class, alloc_geometry);
662
667
  }
663
668
 
664
669
 
@@ -671,7 +676,6 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
671
676
  RGeo_FactoryData* factory_data;
672
677
  GEOSContextHandle_t factory_context;
673
678
  VALUE klasses;
674
- RGeo_Globals* globals;
675
679
  VALUE inferred_klass;
676
680
  char is_collection;
677
681
  RGeo_GeometryData* data;
@@ -680,7 +684,6 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
680
684
  if (geom || !NIL_P(klass)) {
681
685
  factory_data = NIL_P(factory) ? NULL : RGEO_FACTORY_DATA_PTR(factory);
682
686
  factory_context = factory_data ? factory_data->geos_context : NULL;
683
- globals = factory_data ? factory_data->globals : NULL;
684
687
 
685
688
  // We don't allow "empty" points, so replace such objects with
686
689
  // an empty collection.
@@ -688,7 +691,7 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
688
691
  if (GEOSGeomTypeId_r(factory_context, geom) == GEOS_POINT && GEOSGetNumCoordinates_r(factory_context, geom) == 0) {
689
692
  GEOSGeom_destroy_r(factory_context, geom);
690
693
  geom = GEOSGeom_createCollection_r(factory_context, GEOS_GEOMETRYCOLLECTION, NULL, 0);
691
- klass = globals->geos_geometry_collection;
694
+ klass = rgeo_geos_geometry_collection_class;
692
695
  }
693
696
  }
694
697
 
@@ -698,35 +701,35 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
698
701
  is_collection = 0;
699
702
  switch (GEOSGeomTypeId_r(factory_context, geom)) {
700
703
  case GEOS_POINT:
701
- inferred_klass = globals->geos_point;
704
+ inferred_klass = rgeo_geos_point_class;
702
705
  break;
703
706
  case GEOS_LINESTRING:
704
- inferred_klass = globals->geos_line_string;
707
+ inferred_klass = rgeo_geos_line_string_class;
705
708
  break;
706
709
  case GEOS_LINEARRING:
707
- inferred_klass = globals->geos_linear_ring;
710
+ inferred_klass = rgeo_geos_linear_ring_class;
708
711
  break;
709
712
  case GEOS_POLYGON:
710
- inferred_klass = globals->geos_polygon;
713
+ inferred_klass = rgeo_geos_polygon_class;
711
714
  break;
712
715
  case GEOS_MULTIPOINT:
713
- inferred_klass = globals->geos_multi_point;
716
+ inferred_klass = rgeo_geos_multi_point_class;
714
717
  is_collection = 1;
715
718
  break;
716
719
  case GEOS_MULTILINESTRING:
717
- inferred_klass = globals->geos_multi_line_string;
720
+ inferred_klass = rgeo_geos_multi_line_string_class;
718
721
  is_collection = 1;
719
722
  break;
720
723
  case GEOS_MULTIPOLYGON:
721
- inferred_klass = globals->geos_multi_polygon;
724
+ inferred_klass = rgeo_geos_multi_polygon_class;
722
725
  is_collection = 1;
723
726
  break;
724
727
  case GEOS_GEOMETRYCOLLECTION:
725
- inferred_klass = globals->geos_geometry_collection;
728
+ inferred_klass = rgeo_geos_geometry_collection_class;
726
729
  is_collection = 1;
727
730
  break;
728
731
  default:
729
- inferred_klass = globals->geos_geometry;
732
+ inferred_klass = rgeo_geos_geometry_class;
730
733
  break;
731
734
  }
732
735
  if (TYPE(klass) == T_ARRAY && is_collection) {
@@ -745,13 +748,12 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
745
748
  (GEOSPreparedGeometry*)1 : NULL;
746
749
  data->factory = factory;
747
750
  data->klasses = klasses;
748
- result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data);
751
+ result = TypedData_Wrap_Struct(klass, &rgeo_geometry_type, data);
749
752
  }
750
753
  }
751
754
  return result;
752
755
  }
753
756
 
754
-
755
757
  VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VALUE klass)
756
758
  {
757
759
  VALUE result;
@@ -771,21 +773,18 @@ VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VAL
771
773
  const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj, VALUE type)
772
774
  {
773
775
  VALUE object;
774
- const GEOSGeometry* geom;
775
- RGeo_Globals* globals;
776
776
 
777
- if (NIL_P(type) && TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func && RGEO_GEOMETRY_DATA_PTR(obj)->factory == factory) {
777
+ if (NIL_P(type) && RGEO_GEOMETRY_TYPEDDATA_P(obj) && RGEO_GEOMETRY_DATA_PTR(obj)->factory == factory) {
778
778
  object = obj;
779
779
  }
780
780
  else {
781
- globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
782
- object = rb_funcall(globals->feature_module, globals->id_cast, 3, obj, factory, type);
783
- }
784
- geom = NULL;
785
- if (!NIL_P(object)) {
786
- geom = RGEO_GEOMETRY_DATA_PTR(object)->geom;
781
+ object = rb_funcall(rgeo_feature_module, rb_intern("cast"), 3, obj, factory, type);
787
782
  }
788
- return geom;
783
+ if (NIL_P(object))
784
+ return NULL;
785
+
786
+ Check_TypedStruct(object, &rgeo_geometry_type);
787
+ return RGEO_GEOMETRY_DATA_PTR(object)->geom;
789
788
  }
790
789
 
791
790
 
@@ -795,13 +794,11 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
795
794
  GEOSGeometry* geom;
796
795
  RGeo_GeometryData* object_data;
797
796
  const GEOSPreparedGeometry* prep;
798
- RGeo_Globals* globals;
799
797
 
800
798
  if (klasses) {
801
799
  *klasses = Qnil;
802
800
  }
803
- globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
804
- object = rb_funcall(globals->feature_module, globals->id_cast, 5, obj, factory, type, globals->sym_force_new, globals->sym_keep_subtype);
801
+ object = rb_funcall(rgeo_feature_module, rb_intern("cast"), 5, obj, factory, type, ID2SYM(rb_intern("force_new")), ID2SYM(rb_intern("keep_subtype")));
805
802
  geom = NULL;
806
803
  if (!NIL_P(object)) {
807
804
  object_data = RGEO_GEOMETRY_DATA_PTR(object);
@@ -828,13 +825,20 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
828
825
 
829
826
  char rgeo_is_geos_object(VALUE obj)
830
827
  {
831
- return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? 1 : 0;
828
+ return RGEO_GEOMETRY_TYPEDDATA_P(obj) ? 1 : 0;
829
+ }
830
+
831
+ void rgeo_check_geos_object(VALUE obj)
832
+ {
833
+ if (!rgeo_is_geos_object(obj)) {
834
+ rb_raise(rgeo_error, "Not a GEOS Geometry object.");
835
+ }
832
836
  }
833
837
 
834
838
 
835
839
  const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj)
836
840
  {
837
- return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? (const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(obj)->geom) : NULL;
841
+ return RGEO_GEOMETRY_TYPEDDATA_P(obj) ? (const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(obj)->geom) : NULL;
838
842
  }
839
843
 
840
844
 
@@ -922,7 +926,8 @@ VALUE rgeo_geos_klasses_and_factories_eql(VALUE obj1, VALUE obj2)
922
926
  }
923
927
  else {
924
928
  factory = RGEO_GEOMETRY_DATA_PTR(obj1)->factory;
925
- result = rb_funcall(factory, RGEO_FACTORY_DATA_PTR(factory)->globals->id_eql, 1, RGEO_GEOMETRY_DATA_PTR(obj2)->factory);
929
+ /* No need to cache the internal here (https://ips.fastruby.io/4x) */
930
+ result = rb_funcall(factory, rb_intern("eql?"), 1, RGEO_GEOMETRY_DATA_PTR(obj2)->factory);
926
931
  }
927
932
  return result;
928
933
  }
@@ -975,7 +980,7 @@ st_index_t rgeo_geos_objbase_hash(VALUE factory, VALUE type_module, st_index_t h
975
980
  ID hash_method;
976
981
  RGeo_Objbase_Hash_Struct hash_struct;
977
982
 
978
- hash_method = RGEO_FACTORY_DATA_PTR(factory)->globals->id_hash;
983
+ hash_method = rb_intern("hash");
979
984
  hash_struct.seed_hash = hash;
980
985
  hash_struct.h1 = FIX2LONG(rb_funcall(factory, hash_method, 0));
981
986
  hash_struct.h2 = FIX2LONG(rb_funcall(type_module, hash_method, 0));