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

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