rgeo 3.0.0.pre.rc.1 → 3.0.0.pre.rc.2

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -11
  3. data/ext/geos_c_impl/factory.c +31 -30
  4. data/ext/geos_c_impl/factory.h +8 -1
  5. data/ext/geos_c_impl/geometry.c +70 -0
  6. data/ext/geos_c_impl/geometry_collection.c +43 -40
  7. data/ext/geos_c_impl/line_string.c +2 -2
  8. data/ext/geos_c_impl/main.c +1 -1
  9. data/ext/geos_c_impl/polygon.c +29 -22
  10. data/ext/geos_c_impl/preface.h +4 -0
  11. data/ext/geos_c_impl/ruby_more.c +65 -0
  12. data/ext/geos_c_impl/ruby_more.h +16 -0
  13. data/lib/rgeo/cartesian/factory.rb +6 -7
  14. data/lib/rgeo/cartesian/feature_classes.rb +2 -0
  15. data/lib/rgeo/cartesian/feature_methods.rb +16 -0
  16. data/lib/rgeo/cartesian/interface.rb +0 -30
  17. data/lib/rgeo/coord_sys.rb +0 -11
  18. data/lib/rgeo/feature/factory_generator.rb +0 -3
  19. data/lib/rgeo/feature/geometry.rb +79 -0
  20. data/lib/rgeo/geographic/factory.rb +6 -0
  21. data/lib/rgeo/geographic/interface.rb +1 -29
  22. data/lib/rgeo/geographic/projected_feature_methods.rb +16 -0
  23. data/lib/rgeo/geographic/spherical_feature_methods.rb +17 -1
  24. data/lib/rgeo/geos/capi_factory.rb +0 -7
  25. data/lib/rgeo/geos/capi_feature_classes.rb +19 -0
  26. data/lib/rgeo/geos/ffi_factory.rb +6 -7
  27. data/lib/rgeo/geos/ffi_feature_methods.rb +16 -0
  28. data/lib/rgeo/geos/interface.rb +0 -17
  29. data/lib/rgeo/geos/zm_factory.rb +0 -7
  30. data/lib/rgeo/geos/zm_feature_methods.rb +16 -0
  31. data/lib/rgeo/geos.rb +6 -3
  32. data/lib/rgeo/impl_helper/validity_check.rb +3 -2
  33. data/lib/rgeo/version.rb +1 -1
  34. metadata +18 -5
  35. data/lib/rgeo/coord_sys/srs_database/entry.rb +0 -107
  36. data/lib/rgeo/coord_sys/srs_database/sr_org.rb +0 -64
  37. data/lib/rgeo/coord_sys/srs_database/url_reader.rb +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e26b01fb2fff6915756d98e206ee4bdabefeaceadae3cd0b85cb7be9ee6d8285
4
- data.tar.gz: 9b94dd4e6c57e9fa5ab07c7b5fb9c622a52d843b67d146b52454933cb817a4a1
3
+ metadata.gz: 939fdbb8c9bbcb94342b99f952ad5524cb436683ea054bcab0aaa408f362ac2a
4
+ data.tar.gz: 4cd0c59ee3e08947c646c1b7e5c9a9755c44a0a87459437754867bbb5c2e304e
5
5
  SHA512:
6
- metadata.gz: 9adb8cc283c8663fb0a178eeb7a1629fe466265f7fa15c54d4e8dac4188646a2682f591a3e76d12271df5dc6c875961833600b88952d035f824933bd454211de
7
- data.tar.gz: c1f7e26d5a5edcc060cac2efaa782a586c9ee95e1dda08f7af771648ecc1ea2373a1e4ba9053aae00288332e401370c7f61e254367231ceabb4fb36ad5406209
6
+ metadata.gz: e6f02199e30b35334156d3a1107213b6dab9028572e423d2f0f6072a7a2032586e26dfa5a594a8132b33d4071f0d55f6bd75dcd60d1e5a60df4bde0c51b7a78f
7
+ data.tar.gz: 20404c7de6aec61e04eae659253ddf16f518afce40c64274d261acc1a160f5420866c8188fed18425e1a55788e5041ff9b7a93c653f61cdde0a7ce15dccfa1a1
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ## RGeo
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rgeo.svg)](http://badge.fury.io/rb/rgeo)
4
- [![CI](https://github.com/rgeo/rgeo/workflows/CI/badge.svg)](https://github.com/rgeo/rgeo/actions?query=workflow%3ACI+branch%3Amaster+event%3Apush)
4
+ [![CI](https://github.com/rgeo/rgeo/workflows/CI/badge.svg)](https://github.com/rgeo/rgeo/actions?query=workflow%3ACI+branch%3Amain+event%3Apush)
5
5
 
6
6
  RGeo is a geospatial data library for Ruby.
7
7
 
@@ -109,7 +109,7 @@ ActiveRecord connection adapter for SpatiaLite, based on sqlite3 (*not maintaine
109
109
  RDoc Documentation is available at https://www.rubydoc.info/gems/rgeo
110
110
 
111
111
  Contributions are welcome. Please read the
112
- [Contributing guidelines](https://github.com/rgeo/rgeo/blob/master/CONTRIBUTING.md).
112
+ [Contributing guidelines](https://github.com/rgeo/rgeo/blob/main/CONTRIBUTING.md).
113
113
 
114
114
  Support may be available on the
115
115
  [rgeo-users google group](https://groups.google.com/forum/#!forum/rgeo-users)
@@ -124,14 +124,14 @@ generate documentation locally if you're working on RGeo: `yardoc server`.
124
124
 
125
125
  Here's the current list of available topics:
126
126
 
127
- - [An introduction to Spatial Programming With RGeo](https://github.com/rgeo/rgeo/blob/master/doc/An-Introduction-to-Spatial-Programming-With-RGeo.md)
128
- - [Enable GEOS and Proj4 on Heroku](https://github.com/rgeo/rgeo/blob/master/doc/Enable-GEOS-and-Proj4-on-Heroku.md)
129
- - [Installing GEOS](https://github.com/rgeo/rgeo/blob/master/doc/Installing-GEOS.md)
130
- - [Factory Compatibility](https://github.com/rgeo/rgeo/blob/master/doc/Factory-Compatibility.md)
131
- - [Which factory should I use?](https://github.com/rgeo/rgeo/blob/master/doc/Which-factory-should-I-use.md)
132
- - [Geometry validity handling](https://github.com/rgeo/rgeo/blob/master/doc/Geometry-Validity.md)
133
- - [Examples](https://github.com/rgeo/rgeo/blob/master/doc/Examples.md)
134
- - [Who uses `rgeo`?](https://github.com/rgeo/rgeo/blob/master/doc/Gallery.md)
127
+ - [An introduction to Spatial Programming With RGeo](https://github.com/rgeo/rgeo/blob/main/doc/An-Introduction-to-Spatial-Programming-With-RGeo.md)
128
+ - [Enable GEOS and Proj4 on Heroku](https://github.com/rgeo/rgeo/blob/main/doc/Enable-GEOS-and-Proj4-on-Heroku.md)
129
+ - [Installing GEOS](https://github.com/rgeo/rgeo/blob/main/doc/Installing-GEOS.md)
130
+ - [Factory Compatibility](https://github.com/rgeo/rgeo/blob/main/doc/Factory-Compatibility.md)
131
+ - [Which factory should I use?](https://github.com/rgeo/rgeo/blob/main/doc/Which-factory-should-I-use.md)
132
+ - [Geometry validity handling](https://github.com/rgeo/rgeo/blob/main/doc/Geometry-Validity.md)
133
+ - [Examples](https://github.com/rgeo/rgeo/blob/main/doc/Examples.md)
134
+ - [Who uses `rgeo`?](https://github.com/rgeo/rgeo/blob/main/doc/Gallery.md)
135
135
 
136
136
  You can see an exhaustive and up to date list at https://rubydoc.info/gems/rgeo/index.
137
137
  ### Acknowledgments
@@ -158,4 +158,4 @@ by [J Smith](https://github.com/dark-panda).
158
158
 
159
159
  Copyright (c) Daniel Azuma, Tee Parham
160
160
 
161
- [License](https://github.com/rgeo/rgeo/blob/master/LICENSE.txt)
161
+ [License](https://github.com/rgeo/rgeo/blob/main/LICENSE.txt)
@@ -13,15 +13,15 @@
13
13
  #include <stdarg.h>
14
14
  #include <stdio.h>
15
15
 
16
- #include "globals.h"
17
-
16
+ #include "errors.h"
18
17
  #include "factory.h"
18
+ #include "globals.h"
19
19
  #include "geometry.h"
20
- #include "point.h"
20
+ #include "geometry_collection.h"
21
21
  #include "line_string.h"
22
+ #include "point.h"
22
23
  #include "polygon.h"
23
- #include "geometry_collection.h"
24
- #include "errors.h"
24
+ #include "ruby_more.h"
25
25
 
26
26
  RGEO_BEGIN_C
27
27
 
@@ -110,7 +110,7 @@ static void destroy_factory_func(void* data)
110
110
  GEOSWKBWriter_destroy_r(context, factory_data->marshal_wkb_writer);
111
111
  }
112
112
  finishGEOS_r(context);
113
- free(factory_data);
113
+ FREE(factory_data);
114
114
  }
115
115
 
116
116
 
@@ -132,7 +132,7 @@ static void destroy_geometry_func(void* data)
132
132
  {
133
133
  GEOSPreparedGeom_destroy_r(geometry_data->geos_context, prep);
134
134
  }
135
- free(geometry_data);
135
+ FREE(geometry_data);
136
136
  }
137
137
 
138
138
 
@@ -546,7 +546,7 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
546
546
  result = TypedData_Wrap_Struct(klass, &rgeo_factory_type, data);
547
547
  }
548
548
  else {
549
- free(data);
549
+ FREE(data);
550
550
  }
551
551
  }
552
552
  return result;
@@ -860,38 +860,39 @@ const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj, VALU
860
860
  return RGEO_GEOMETRY_DATA_PTR(object)->geom;
861
861
  }
862
862
 
863
-
864
- GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, VALUE type, VALUE* klasses)
863
+ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, VALUE type, VALUE* klasses, int *state)
865
864
  {
866
865
  VALUE object;
867
866
  GEOSGeometry* geom;
868
867
  RGeo_GeometryData* object_data;
869
868
  const GEOSPreparedGeometry* prep;
870
-
871
869
  if (klasses) {
872
870
  *klasses = Qnil;
873
871
  }
874
- object = rb_funcall(rgeo_feature_module, rb_intern("cast"), 5, obj, factory, type, ID2SYM(rb_intern("force_new")), ID2SYM(rb_intern("keep_subtype")));
875
- geom = NULL;
876
- if (!NIL_P(object)) {
877
- object_data = RGEO_GEOMETRY_DATA_PTR(object);
878
- geom = object_data->geom;
879
- if (klasses) {
880
- *klasses = object_data->klasses;
881
- if (NIL_P(*klasses)) {
882
- *klasses = CLASS_OF(object);
883
- }
884
- }
885
- prep = object_data->prep;
886
- if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
887
- GEOSPreparedGeom_destroy_r(object_data->geos_context, prep);
872
+
873
+ object = rb_protect_funcall(rgeo_feature_module, rb_intern("cast"), state, 5, obj, factory, type, ID2SYM(rb_intern("force_new")), ID2SYM(rb_intern("keep_subtype")));
874
+ if (*state || NIL_P(object)) {
875
+ return NULL;
876
+ }
877
+
878
+ object_data = RGEO_GEOMETRY_DATA_PTR(object);
879
+ geom = object_data->geom;
880
+ if (klasses) {
881
+ *klasses = object_data->klasses;
882
+ if (NIL_P(*klasses)) {
883
+ *klasses = CLASS_OF(object);
888
884
  }
889
- object_data->geos_context = NULL;
890
- object_data->geom = NULL;
891
- object_data->prep = NULL;
892
- object_data->factory = Qnil;
893
- object_data->klasses = Qnil;
894
885
  }
886
+ prep = object_data->prep;
887
+ if (prep && prep != (GEOSPreparedGeometry*)1 && prep != (GEOSPreparedGeometry*)2) {
888
+ GEOSPreparedGeom_destroy_r(object_data->geos_context, prep);
889
+ }
890
+ object_data->geos_context = NULL;
891
+ object_data->geom = NULL;
892
+ object_data->prep = NULL;
893
+ object_data->factory = Qnil;
894
+ object_data->klasses = Qnil;
895
+
895
896
  return geom;
896
897
  }
897
898
 
@@ -167,8 +167,15 @@ const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj, VALU
167
167
  result of this function to build a GEOS-backed clone of the original
168
168
  geometry, or to include the given geometry in a collection while keeping
169
169
  the klasses intact.
170
+
171
+ The state parameter is given to follow `rb_protect*` ruby methods: this
172
+ method calls `#cast`, and this call may raise. if it does raise, state
173
+ will be set to a non-zero value, and you'll have access to the error
174
+ in `rb_errinfo()`. IT IS THE CALLER'S RESPONSIBILITY TO PROPAGATE THE
175
+ ERROR. You could also discard the error with `rb_set_errinfo(Qnil)`,
176
+ this will just ignore the error altogether.
170
177
  */
171
- GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, VALUE type, VALUE* klasses);
178
+ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, VALUE type, VALUE* klasses, int* state);
172
179
 
173
180
  /*
174
181
  Returns 1 if the given ruby object is a GEOS Geometry implementation,
@@ -386,6 +386,11 @@ static VALUE method_geometry_equals(VALUE self, VALUE rhs)
386
386
  GEOSContextHandle_t self_context;
387
387
  char val;
388
388
 
389
+ // Shortcut when self and rhs are the same object.
390
+ if (self == rhs) {
391
+ return Qtrue;
392
+ }
393
+
389
394
  result = Qnil;
390
395
  self_data = RGEO_GEOMETRY_DATA_PTR(self);
391
396
  self_geom = self_data->geom;
@@ -1058,6 +1063,32 @@ static VALUE method_geometry_invalid_reason(VALUE self)
1058
1063
  return result;
1059
1064
  }
1060
1065
 
1066
+ static VALUE method_geometry_invalid_reason_location(VALUE self)
1067
+ {
1068
+ VALUE result;
1069
+ RGeo_GeometryData* self_data;
1070
+ const GEOSGeometry* self_geom;
1071
+ GEOSGeometry* location = NULL;
1072
+
1073
+ result = Qnil;
1074
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
1075
+ self_geom = self_data->geom;
1076
+ if (self_geom) {
1077
+ // We use NULL there to tell GEOS that we don't care about the reason.
1078
+ switch(GEOSisValidDetail_r(self_data->geos_context, self_geom, 0, NULL, &location)) {
1079
+ case 0: // invalid
1080
+ result = rgeo_wrap_geos_geometry(self_data->factory, location, Qnil);
1081
+ case 1: // valid
1082
+ break;
1083
+ case 2: // exception
1084
+ break;
1085
+ default:
1086
+ break;
1087
+ };
1088
+ }
1089
+ return result;
1090
+ }
1091
+
1061
1092
  static VALUE method_geometry_make_valid(VALUE self)
1062
1093
  {
1063
1094
  RGeo_GeometryData* self_data;
@@ -1090,6 +1121,43 @@ static VALUE method_geometry_point_on_surface(VALUE self)
1090
1121
  return result;
1091
1122
  }
1092
1123
 
1124
+ /**
1125
+ * call-seq:
1126
+ * some.polygonize -> RGeo::Feature::GeometryCollection
1127
+ *
1128
+ * Polygonizes a set of Geometries which contain linework that
1129
+ * represents the edges of a planar graph.
1130
+ *
1131
+ * All types of Geometry are accepted as input;
1132
+ * the constituent linework is extracted as the edges to be polygonized.
1133
+ *
1134
+ * The edges must be correctly noded;
1135
+ * that is, they must only meet at their endpoints and not overlap anywhere.
1136
+ *
1137
+ * @see https://libgeos.org/doxygen/geos__c_8h.html#a9d98e448d3b846d591c726d1c0000d25 GEOSPolygonize
1138
+ */
1139
+ static VALUE method_geometry_polygonize(VALUE self)
1140
+ {
1141
+ VALUE result;
1142
+ RGeo_GeometryData* self_data;
1143
+ const GEOSGeometry* self_geom;
1144
+ GEOSGeometry* geos_polygon_collection;
1145
+
1146
+ result = Qnil;
1147
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
1148
+ self_geom = self_data->geom;
1149
+ if (self_geom) {
1150
+ geos_polygon_collection = GEOSPolygonize_r(self_data->geos_context, &self_geom, 1);
1151
+
1152
+ if (geos_polygon_collection == NULL) {
1153
+ rb_raise(rb_eGeosError, "GEOS can't polygonize this geometry.");
1154
+ }
1155
+
1156
+ result = rgeo_wrap_geos_geometry(self_data->factory, geos_polygon_collection, Qnil);
1157
+ }
1158
+ return result;
1159
+ }
1160
+
1093
1161
  VALUE rgeo_geos_geometries_strict_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2)
1094
1162
  {
1095
1163
  switch (GEOSEqualsExact_r(context, geom1, geom2, 0.0)) {
@@ -1156,8 +1224,10 @@ void rgeo_init_geos_geometry()
1156
1224
  rb_define_method(geos_geometry_methods, "sym_difference", method_geometry_sym_difference, 1);
1157
1225
  rb_define_method(geos_geometry_methods, "valid?", method_geometry_is_valid, 0);
1158
1226
  rb_define_method(geos_geometry_methods, "invalid_reason", method_geometry_invalid_reason, 0);
1227
+ rb_define_method(geos_geometry_methods, "invalid_reason_location", method_geometry_invalid_reason_location, 0);
1159
1228
  rb_define_method(geos_geometry_methods, "point_on_surface", method_geometry_point_on_surface, 0);
1160
1229
  rb_define_method(geos_geometry_methods, "make_valid", method_geometry_make_valid, 0);
1230
+ rb_define_method(geos_geometry_methods, "polygonize", method_geometry_polygonize, 0);
1161
1231
  }
1162
1232
 
1163
1233
 
@@ -10,16 +10,16 @@
10
10
  #include <ruby.h>
11
11
  #include <geos_c.h>
12
12
 
13
- #include "globals.h"
14
13
 
14
+ #include "coordinates.h"
15
+ #include "errors.h"
15
16
  #include "factory.h"
16
17
  #include "geometry.h"
18
+ #include "geometry_collection.h"
19
+ #include "globals.h"
17
20
  #include "line_string.h"
18
21
  #include "polygon.h"
19
- #include "geometry.h"
20
- #include "geometry_collection.h"
21
22
 
22
- #include "coordinates.h"
23
23
 
24
24
  RGEO_BEGIN_C
25
25
 
@@ -44,17 +44,19 @@ static VALUE create_geometry_collection(VALUE module, int type, VALUE factory, V
44
44
  VALUE cast_type;
45
45
  GEOSGeometry* geom;
46
46
  GEOSGeometry* collection;
47
+ int state = 0;
47
48
 
48
49
  result = Qnil;
49
50
  Check_Type(array, T_ARRAY);
50
51
  len = (unsigned int)RARRAY_LEN(array);
51
52
  geoms = ALLOC_N(GEOSGeometry*, len == 0 ? 1 : len);
52
- if (geoms) {
53
- factory_data = RGEO_FACTORY_DATA_PTR(factory);
54
- geos_context = factory_data->geos_context;
55
- klasses = Qnil;
56
- cast_type = Qnil;
57
- switch (type) {
53
+ if (!geoms) { rb_raise(rb_eRGeoError, "not enough memory available"); }
54
+
55
+ factory_data = RGEO_FACTORY_DATA_PTR(factory);
56
+ geos_context = factory_data->geos_context;
57
+ klasses = Qnil;
58
+ cast_type = Qnil;
59
+ switch (type) {
58
60
  case GEOS_MULTIPOINT:
59
61
  cast_type = rgeo_feature_point_module;
60
62
  break;
@@ -64,46 +66,47 @@ static VALUE create_geometry_collection(VALUE module, int type, VALUE factory, V
64
66
  case GEOS_MULTIPOLYGON:
65
67
  cast_type = rgeo_feature_polygon_module;
66
68
  break;
69
+ }
70
+ for (i=0; i<len; ++i) {
71
+ geom = rgeo_convert_to_detached_geos_geometry(rb_ary_entry(array, i), factory, cast_type, &klass, &state);
72
+ if (state || !geom) {
73
+ break;
67
74
  }
68
- for (i=0; i<len; ++i) {
69
- geom = rgeo_convert_to_detached_geos_geometry(rb_ary_entry(array, i), factory, cast_type, &klass);
70
- if (!geom) {
71
- break;
72
- }
73
- geoms[i] = geom;
74
- if (!NIL_P(klass) && NIL_P(klasses)) {
75
- klasses = rb_ary_new2(len);
76
- for (j=0; j<i; ++j) {
77
- rb_ary_push(klasses, Qnil);
78
- }
79
- }
80
- if (!NIL_P(klasses)) {
81
- rb_ary_push(klasses, klass);
82
- }
83
- }
84
- if (i != len) {
75
+ geoms[i] = geom;
76
+ if (!NIL_P(klass) && NIL_P(klasses)) {
77
+ klasses = rb_ary_new2(len);
85
78
  for (j=0; j<i; ++j) {
86
- GEOSGeom_destroy_r(geos_context, geoms[j]);
79
+ rb_ary_push(klasses, Qnil);
87
80
  }
88
81
  }
89
- else {
90
- collection = GEOSGeom_createCollection_r(geos_context, type, geoms, len);
91
- if (collection) {
92
- result = rgeo_wrap_geos_geometry(factory, collection, module);
93
- RGEO_GEOMETRY_DATA_PTR(result)->klasses = klasses;
94
- }
95
- // NOTE: We are assuming that GEOS will do its own cleanup of the
96
- // element geometries if it fails to create the collection, so we
97
- // are not doing that ourselves. If that turns out not to be the
98
- // case, this will be a memory leak.
82
+ if (!NIL_P(klasses)) {
83
+ rb_ary_push(klasses, klass);
99
84
  }
100
- free(geoms);
85
+ }
86
+ if (i != len) {
87
+ for (j=0; j<i; ++j) {
88
+ GEOSGeom_destroy_r(geos_context, geoms[j]);
89
+ }
90
+ }
91
+ else {
92
+ collection = GEOSGeom_createCollection_r(geos_context, type, geoms, len);
93
+ if (collection) {
94
+ result = rgeo_wrap_geos_geometry(factory, collection, module);
95
+ RGEO_GEOMETRY_DATA_PTR(result)->klasses = klasses;
96
+ }
97
+ // NOTE: We are assuming that GEOS will do its own cleanup of the
98
+ // element geometries if it fails to create the collection, so we
99
+ // are not doing that ourselves. If that turns out not to be the
100
+ // case, this will be a memory leak.
101
+ }
102
+ FREE(geoms);
103
+ if (state) {
104
+ rb_exc_raise(rb_errinfo()); // raise $!
101
105
  }
102
106
 
103
107
  return result;
104
108
  }
105
109
 
106
-
107
110
  /**** RUBY METHOD DEFINITIONS ****/
108
111
 
109
112
 
@@ -447,7 +447,7 @@ static GEOSCoordSequence* coord_seq_from_array(VALUE factory, VALUE array, char
447
447
  }
448
448
  }
449
449
  if (!good) {
450
- free(coords);
450
+ FREE(coords);
451
451
  return NULL;
452
452
  }
453
453
  }
@@ -472,7 +472,7 @@ static GEOSCoordSequence* coord_seq_from_array(VALUE factory, VALUE array, char
472
472
  GEOSCoordSeq_setZ_r(context, coord_seq, len, has_z ? coords[2] : 0);
473
473
  }
474
474
  }
475
- free(coords);
475
+ FREE(coords);
476
476
  return coord_seq;
477
477
  }
478
478
 
@@ -9,8 +9,8 @@
9
9
  #include <ruby.h>
10
10
  #include <geos_c.h>
11
11
 
12
+ #include "ruby_more.h"
12
13
  #include "globals.h"
13
-
14
14
  #include "errors.h"
15
15
 
16
16
  #include "factory.h"
@@ -241,37 +241,44 @@ static VALUE cmethod_create(VALUE module, VALUE factory, VALUE exterior, VALUE i
241
241
  unsigned int i;
242
242
  GEOSGeometry* interior_geom;
243
243
  GEOSGeometry* polygon;
244
+ int state = 0;
244
245
 
245
246
  Check_Type(interior_array, T_ARRAY);
246
247
  factory_data = RGEO_FACTORY_DATA_PTR(factory);
247
248
  linear_ring_type = rgeo_feature_linear_ring_module;
248
- exterior_geom = rgeo_convert_to_detached_geos_geometry(exterior, factory, linear_ring_type, NULL);
249
- if (exterior_geom) {
250
- context = factory_data->geos_context;
251
- len = (unsigned int)RARRAY_LEN(interior_array);
252
- interior_geoms = ALLOC_N(GEOSGeometry*, len == 0 ? 1 : len);
253
- if (interior_geoms) {
254
- actual_len = 0;
255
- for (i=0; i<len; ++i) {
256
- interior_geom = rgeo_convert_to_detached_geos_geometry(rb_ary_entry(interior_array, i), factory, linear_ring_type, NULL);
257
- if (interior_geom) {
258
- interior_geoms[actual_len++] = interior_geom;
259
- }
249
+ exterior_geom = rgeo_convert_to_detached_geos_geometry(exterior, factory, linear_ring_type, NULL, &state);
250
+ if (state) { rb_exc_raise(rb_errinfo()); }
251
+ if (!exterior_geom) { return Qnil; }
252
+
253
+ context = factory_data->geos_context;
254
+ len = (unsigned int)RARRAY_LEN(interior_array);
255
+ interior_geoms = ALLOC_N(GEOSGeometry*, len == 0 ? 1 : len);
256
+ if (interior_geoms) {
257
+ actual_len = 0;
258
+ for (i=0; i<len; ++i) {
259
+ interior_geom = rgeo_convert_to_detached_geos_geometry(rb_ary_entry(interior_array, i), factory, linear_ring_type, NULL, &state);
260
+ if (interior_geom) {
261
+ interior_geoms[actual_len++] = interior_geom;
260
262
  }
261
- if (len == actual_len) {
262
- polygon = GEOSGeom_createPolygon_r(context, exterior_geom, interior_geoms, actual_len);
263
- if (polygon) {
264
- free(interior_geoms);
265
- return rgeo_wrap_geos_geometry(factory, polygon, rgeo_geos_polygon_class);
266
- }
263
+ if (state) {
264
+ break;
267
265
  }
268
- for (i=0; i<actual_len; ++i) {
269
- GEOSGeom_destroy_r(context, interior_geoms[i]);
266
+ }
267
+ if (len == actual_len) {
268
+ polygon = GEOSGeom_createPolygon_r(context, exterior_geom, interior_geoms, actual_len);
269
+ if (polygon) {
270
+ FREE(interior_geoms);
271
+ // NOTE: we can return safely here, state cannot be other than 0.
272
+ return rgeo_wrap_geos_geometry(factory, polygon, rgeo_geos_polygon_class);
270
273
  }
271
- free(interior_geoms);
272
274
  }
273
- GEOSGeom_destroy_r(context, exterior_geom);
275
+ for (i=0; i<actual_len; ++i) {
276
+ GEOSGeom_destroy_r(context, interior_geoms[i]);
277
+ }
278
+ FREE(interior_geoms);
274
279
  }
280
+ GEOSGeom_destroy_r(context, exterior_geom);
281
+ if (state) { rb_exc_raise(rb_errinfo()); }
275
282
  return Qnil;
276
283
  }
277
284
 
@@ -50,3 +50,7 @@
50
50
 
51
51
  // https://ozlabs.org/~rusty/index.cgi/tech/2008-04-01.html
52
52
  #define streq(a, b) (!strcmp((a),(b)))
53
+
54
+ // When using ruby ALLOC* macros, we are using ruby_xmalloc, which counterpart
55
+ // is ruby_xfree. This macro helps enforcing that by showing us the way.
56
+ #define FREE ruby_xfree
@@ -0,0 +1,65 @@
1
+ /*
2
+ Utilities for the ruby CAPI
3
+ */
4
+
5
+ #ifndef RGEO_GEOS_RUBY_MORE_INCLUDED
6
+ #define RGEO_GEOS_RUBY_MORE_INCLUDED
7
+
8
+ #include <ruby.h>
9
+
10
+ #include "preface.h"
11
+ #include "ruby_more.h"
12
+
13
+ RGEO_BEGIN_C
14
+
15
+ struct funcall_args
16
+ {
17
+ VALUE recv;
18
+ ID mid;
19
+ int argc;
20
+ VALUE *argv;
21
+ };
22
+
23
+ static VALUE inner_funcall(VALUE args_)
24
+ {
25
+ struct funcall_args *args = (struct funcall_args *)args_;
26
+ return rb_funcallv(
27
+ args->recv,
28
+ args->mid,
29
+ args->argc,
30
+ args->argv);
31
+ }
32
+
33
+ VALUE rb_protect_funcall(VALUE recv, ID mid, int *state, int n, ...)
34
+ {
35
+ struct funcall_args args;
36
+ VALUE *argv;
37
+ va_list ar;
38
+
39
+ if (n > 0)
40
+ {
41
+ long i;
42
+ va_start(ar, n);
43
+ argv = ALLOCA_N(VALUE, n);
44
+ for (i = 0; i < n; i++)
45
+ {
46
+ argv[i] = va_arg(ar, VALUE);
47
+ }
48
+ va_end(ar);
49
+ }
50
+ else
51
+ {
52
+ argv = 0;
53
+ }
54
+
55
+ args.recv = recv;
56
+ args.mid = mid;
57
+ args.argc = n;
58
+ args.argv = argv;
59
+
60
+ return rb_protect(inner_funcall, (VALUE)&args, state);
61
+ }
62
+
63
+ RGEO_END_C
64
+
65
+ #endif
@@ -0,0 +1,16 @@
1
+ /*
2
+ Utilities for the ruby CAPI
3
+ */
4
+
5
+ #ifndef RGEO_GEOS_RUBY_MORE_INCLUDED
6
+ #define RGEO_GEOS_RUBY_MORE_INCLUDED
7
+
8
+ #include <ruby.h>
9
+
10
+ RGEO_BEGIN_C
11
+
12
+ VALUE rb_protect_funcall(VALUE recv, ID mid, int *state, int n, ...);
13
+
14
+ RGEO_END_C
15
+
16
+ #endif
@@ -22,6 +22,11 @@ module RGeo
22
22
  def initialize(opts = {})
23
23
  @has_z = opts[:has_z_coordinate] ? true : false
24
24
  @has_m = opts[:has_m_coordinate] ? true : false
25
+ @coordinate_dimension = 2
26
+ @coordinate_dimension += 1 if @has_z
27
+ @coordinate_dimension += 1 if @has_m
28
+ @spatial_dimension = @has_z ? 3 : 2
29
+
25
30
  @proj4 = opts[:proj4]
26
31
  if @proj4 && CoordSys.check!(:proj4)
27
32
  if @proj4.is_a?(String) || @proj4.is_a?(Hash)
@@ -33,13 +38,6 @@ module RGeo
33
38
  if @coord_sys.is_a?(String)
34
39
  @coord_sys = CoordSys::CS.create_from_wkt(@coord_sys)
35
40
  end
36
- if (!@proj4 || !@coord_sys) && srid && (db = opts[:srs_database])
37
- entry = db.get(srid.to_i)
38
- if entry
39
- @proj4 ||= entry.proj4
40
- @coord_sys ||= entry.coord_sys
41
- end
42
- end
43
41
  srid ||= @coord_sys.authority_code if @coord_sys
44
42
  @srid = srid.to_i
45
43
  @buffer_resolution = opts[:buffer_resolution].to_i
@@ -74,6 +72,7 @@ module RGeo
74
72
  @wkb_parser = WKRep::WKBParser.new(self)
75
73
  end
76
74
  end
75
+ attr_reader :coordinate_dimension, :spatial_dimension
77
76
 
78
77
  # Equivalence test.
79
78
 
@@ -6,6 +6,8 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ require_relative "../impl_helper/validity_check"
10
+
9
11
  module RGeo
10
12
  module Cartesian
11
13
  class PointImpl # :nodoc:
@@ -17,6 +17,22 @@ module RGeo
17
17
  BoundingBox.new(factory).add(self).to_geometry
18
18
  end
19
19
 
20
+ def coordinate_dimension
21
+ factory.coordinate_dimension
22
+ end
23
+
24
+ def spatial_dimension
25
+ factory.spatial_dimension
26
+ end
27
+
28
+ def is_3d?
29
+ factory.property(:has_z_coordinate)
30
+ end
31
+
32
+ def measured?
33
+ factory.property(:has_m_coordinate)
34
+ end
35
+
20
36
  private
21
37
 
22
38
  def graph