rgeo 2.1.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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));