rgeo 2.3.0 → 3.0.0.pre.rc.1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/README.md +1 -0
  4. data/ext/geos_c_impl/analysis.c +8 -6
  5. data/ext/geos_c_impl/analysis.h +1 -3
  6. data/ext/geos_c_impl/errors.c +10 -8
  7. data/ext/geos_c_impl/errors.h +7 -3
  8. data/ext/geos_c_impl/extconf.rb +3 -0
  9. data/ext/geos_c_impl/factory.c +251 -182
  10. data/ext/geos_c_impl/factory.h +43 -62
  11. data/ext/geos_c_impl/geometry.c +56 -24
  12. data/ext/geos_c_impl/geometry.h +8 -3
  13. data/ext/geos_c_impl/geometry_collection.c +41 -148
  14. data/ext/geos_c_impl/geometry_collection.h +1 -14
  15. data/ext/geos_c_impl/globals.c +91 -0
  16. data/ext/geos_c_impl/globals.h +45 -0
  17. data/ext/geos_c_impl/line_string.c +28 -29
  18. data/ext/geos_c_impl/line_string.h +1 -3
  19. data/ext/geos_c_impl/main.c +10 -9
  20. data/ext/geos_c_impl/point.c +9 -8
  21. data/ext/geos_c_impl/point.h +1 -3
  22. data/ext/geos_c_impl/polygon.c +15 -51
  23. data/ext/geos_c_impl/polygon.h +1 -3
  24. data/ext/geos_c_impl/preface.h +8 -0
  25. data/lib/rgeo/cartesian/analysis.rb +2 -2
  26. data/lib/rgeo/cartesian/calculations.rb +54 -17
  27. data/lib/rgeo/cartesian/factory.rb +0 -7
  28. data/lib/rgeo/cartesian/feature_classes.rb +66 -46
  29. data/lib/rgeo/cartesian/feature_methods.rb +56 -20
  30. data/lib/rgeo/cartesian/interface.rb +0 -6
  31. data/lib/rgeo/cartesian/planar_graph.rb +379 -0
  32. data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
  33. data/lib/rgeo/cartesian/valid_op.rb +71 -0
  34. data/lib/rgeo/cartesian.rb +3 -0
  35. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
  36. data/lib/rgeo/error.rb +15 -0
  37. data/lib/rgeo/feature/curve.rb +12 -2
  38. data/lib/rgeo/feature/geometry.rb +38 -28
  39. data/lib/rgeo/feature/geometry_collection.rb +13 -5
  40. data/lib/rgeo/feature/line_string.rb +3 -3
  41. data/lib/rgeo/feature/multi_curve.rb +6 -1
  42. data/lib/rgeo/feature/multi_surface.rb +3 -3
  43. data/lib/rgeo/feature/point.rb +4 -4
  44. data/lib/rgeo/feature/surface.rb +3 -3
  45. data/lib/rgeo/geographic/factory.rb +0 -7
  46. data/lib/rgeo/geographic/interface.rb +4 -18
  47. data/lib/rgeo/geographic/proj4_projector.rb +0 -2
  48. data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
  49. data/lib/rgeo/geographic/projected_feature_methods.rb +63 -30
  50. data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
  51. data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
  52. data/lib/rgeo/geographic/spherical_feature_methods.rb +68 -2
  53. data/lib/rgeo/geos/capi_factory.rb +21 -31
  54. data/lib/rgeo/geos/capi_feature_classes.rb +64 -11
  55. data/lib/rgeo/geos/ffi_factory.rb +0 -28
  56. data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
  57. data/lib/rgeo/geos/ffi_feature_methods.rb +53 -10
  58. data/lib/rgeo/geos/interface.rb +18 -10
  59. data/lib/rgeo/geos/zm_factory.rb +0 -12
  60. data/lib/rgeo/geos/zm_feature_methods.rb +30 -5
  61. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +18 -8
  62. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
  63. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +37 -26
  64. data/lib/rgeo/impl_helper/basic_point_methods.rb +13 -3
  65. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +8 -3
  66. data/lib/rgeo/impl_helper/valid_op.rb +354 -0
  67. data/lib/rgeo/impl_helper/validity_check.rb +138 -0
  68. data/lib/rgeo/impl_helper.rb +1 -0
  69. data/lib/rgeo/version.rb +1 -1
  70. data/lib/rgeo/wkrep/wkb_generator.rb +1 -1
  71. data/lib/rgeo/wkrep/wkt_generator.rb +6 -6
  72. metadata +30 -7
@@ -10,58 +10,13 @@
10
10
 
11
11
  RGEO_BEGIN_C
12
12
 
13
- /*
14
- Per-interpreter globals.
15
- Most of these are cached references to commonly used classes, modules,
16
- and symbols so we don't have to do a lot of constant lookups and calls
17
- to rb_intern.
18
- */
19
- typedef struct {
20
- VALUE feature_module;
21
- VALUE feature_geometry;
22
- VALUE feature_point;
23
- VALUE feature_line_string;
24
- VALUE feature_linear_ring;
25
- VALUE feature_line;
26
- VALUE feature_polygon;
27
- VALUE feature_geometry_collection;
28
- VALUE feature_multi_point;
29
- VALUE feature_multi_line_string;
30
- VALUE feature_multi_polygon;
31
- VALUE geos_module;
32
- VALUE geos_geometry;
33
- VALUE geos_point;
34
- VALUE geos_line_string;
35
- VALUE geos_linear_ring;
36
- VALUE geos_line;
37
- VALUE geos_polygon;
38
- VALUE geos_geometry_collection;
39
- VALUE geos_multi_point;
40
- VALUE geos_multi_line_string;
41
- VALUE geos_multi_polygon;
42
- ID id_cast;
43
- ID id_eql;
44
- ID id_generate;
45
- ID id_enum_for;
46
- ID id_hash;
47
- VALUE sym_force_new;
48
- VALUE sym_keep_subtype;
49
- #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
50
- VALUE psych_wkt_generator;
51
- VALUE marshal_wkb_generator;
52
- #endif
53
- } RGeo_Globals;
54
-
55
-
56
13
  /*
57
14
  Wrapped structure for Factory objects.
58
15
  A factory encapsulates the GEOS context, and GEOS serializer settings.
59
16
  It also stores the SRID for all geometries created by this factory,
60
17
  and the resolution for buffers created for this factory's geometries.
61
- Finally, it provides easy access to the globals.
62
18
  */
63
19
  typedef struct {
64
- RGeo_Globals* globals;
65
20
  GEOSContextHandle_t geos_context;
66
21
  GEOSWKTReader* wkt_reader;
67
22
  GEOSWKBReader* wkb_reader;
@@ -82,12 +37,35 @@ typedef struct {
82
37
  int buffer_resolution;
83
38
  } RGeo_FactoryData;
84
39
 
85
- #define RGEO_FACTORYFLAGS_LENIENT_MULTIPOLYGON 1
86
- #define RGEO_FACTORYFLAGS_SUPPORTS_Z 2
87
- #define RGEO_FACTORYFLAGS_SUPPORTS_M 4
88
- #define RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M 6
89
- #define RGEO_FACTORYFLAGS_PREPARE_HEURISTIC 8
40
+ /*
41
+ Flags that are used to pass options when creating a factory.
42
+ They are available in ruby under RGeo::Geos::CAPIFactory::FLAG_name
43
+ where name is the name below without the RGEO_FACTORYFLAGS_ prefix.
44
+ */
45
+ #define RGEO_FACTORYFLAGS_SUPPORTS_Z 0b0010
46
+ #define RGEO_FACTORYFLAGS_SUPPORTS_M 0b0100
47
+ #define RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M (RGEO_FACTORYFLAGS_SUPPORTS_Z | RGEO_FACTORYFLAGS_SUPPORTS_M)
48
+ #define RGEO_FACTORYFLAGS_PREPARE_HEURISTIC 0b1000
49
+
50
+ /* call-seq:
51
+ * RGeo::Geos::CAPIFactory.supports_z? -> true or false
52
+ */
53
+ VALUE method_factory_supports_z_p(VALUE self);
54
+
55
+ /* call-seq:
56
+ * RGeo::Geos::CAPIFactory.supports_m? -> true or false
57
+ */
58
+ VALUE method_factory_supports_m_p(VALUE self);
90
59
 
60
+ /* call-seq:
61
+ * RGeo::Geos::CAPIFactory.supports_z_or_m? -> true or false
62
+ */
63
+ VALUE method_factory_supports_z_or_m_p(VALUE self);
64
+
65
+ /* call-seq:
66
+ * RGeo::Geos::CAPIFactory.prepare_heuristic? -> true or false
67
+ */
68
+ VALUE method_factory_prepare_heuristic_p(VALUE self);
91
69
 
92
70
  /*
93
71
  Wrapped structure for Geometry objects.
@@ -119,18 +97,30 @@ typedef struct {
119
97
  } RGeo_GeometryData;
120
98
 
121
99
 
100
+ // Data types which indicate how RGeo types should be managed by Ruby.
101
+ extern const rb_data_type_t rgeo_factory_type;
102
+
103
+ extern const rb_data_type_t rgeo_geometry_type;
104
+
105
+
106
+ // Convenient macros for checking the type of data from Ruby
107
+ #define RGEO_FACTORY_TYPEDDATA_P(object) (_RGEO_TYPEDDATA_P(object, &rgeo_factory_type))
108
+ #define RGEO_GEOMETRY_TYPEDDATA_P(object) (_RGEO_TYPEDDATA_P(object, &rgeo_geometry_type))
109
+
110
+ #define _RGEO_TYPEDDATA_P(object, data_type) (TYPE(object) == T_DATA && RTYPEDDATA(object)->typed_flag == 1 && RTYPEDDATA(object)->type == data_type)
111
+
122
112
  // Returns the RGeo_FactoryData* given a ruby Factory object
123
- #define RGEO_FACTORY_DATA_PTR(factory) ((RGeo_FactoryData*)DATA_PTR(factory))
113
+ #define RGEO_FACTORY_DATA_PTR(factory) ((RGeo_FactoryData*)RTYPEDDATA_DATA(factory))
124
114
 
125
115
  // Returns the RGeo_GeometryData* given a ruby Geometry object
126
- #define RGEO_GEOMETRY_DATA_PTR(geometry) ((RGeo_GeometryData*)DATA_PTR(geometry))
116
+ #define RGEO_GEOMETRY_DATA_PTR(geometry) ((RGeo_GeometryData*)RTYPEDDATA_DATA(geometry))
127
117
 
128
118
 
129
119
  /*
130
120
  Initializes the factory module. This should be called first in the
131
121
  initialization process.
132
122
  */
133
- RGeo_Globals* rgeo_init_geos_factory();
123
+ void rgeo_init_geos_factory();
134
124
 
135
125
  /*
136
126
  Given a GEOS geometry handle, wraps it in a ruby Geometry object of the
@@ -197,15 +187,6 @@ void rgeo_check_geos_object(VALUE obj);
197
187
  */
198
188
  const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj);
199
189
 
200
- /*
201
- Compares the coordinate sequences for two given GEOS geometries.
202
- The two given geometries MUST be of types backed directly by
203
- coordinate sequences-- i.e. points or line strings.
204
- Returns Qtrue if the two coordinate sequences are equal, Qfalse
205
- if they are inequal, or Qnil if an error occurs.
206
- */
207
- VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
208
-
209
190
  /*
210
191
  Compares the ruby classes and geometry factories of the two given ruby
211
192
  objects. Returns Qtrue if everything is equal (that is, the two objects
@@ -11,6 +11,9 @@
11
11
  #include <ruby.h>
12
12
  #include <geos_c.h>
13
13
 
14
+ #include "globals.h"
15
+
16
+ #include "errors.h"
14
17
  #include "factory.h"
15
18
  #include "geometry.h"
16
19
 
@@ -180,13 +183,11 @@ static VALUE method_geometry_geometry_type(VALUE self)
180
183
  {
181
184
  VALUE result;
182
185
  RGeo_GeometryData* self_data;
183
- const GEOSGeometry* self_geom;
184
186
 
185
187
  result = Qnil;
186
188
  self_data = RGEO_GEOMETRY_DATA_PTR(self);
187
- self_geom = self_data->geom;
188
- if (self_geom) {
189
- result = RGEO_FACTORY_DATA_PTR(self_data->factory)->globals->feature_geometry;
189
+ if (self_data->geom) {
190
+ result = rgeo_feature_geometry_module;
190
191
  }
191
192
  return result;
192
193
  }
@@ -271,7 +272,7 @@ static VALUE method_geometry_as_text(VALUE self)
271
272
  factory_data = RGEO_FACTORY_DATA_PTR(self_data->factory);
272
273
  wkt_generator = factory_data->wkrep_wkt_generator;
273
274
  if (!NIL_P(wkt_generator)) {
274
- result = rb_funcall(wkt_generator, factory_data->globals->id_generate, 1, self);
275
+ result = rb_funcall(wkt_generator, rb_intern("generate"), 1, self);
275
276
  }
276
277
  else {
277
278
  wkt_writer = factory_data->wkt_writer;
@@ -310,7 +311,7 @@ static VALUE method_geometry_as_binary(VALUE self)
310
311
  factory_data = RGEO_FACTORY_DATA_PTR(self_data->factory);
311
312
  wkb_generator = factory_data->wkrep_wkb_generator;
312
313
  if (!NIL_P(wkb_generator)) {
313
- result = rb_funcall(wkb_generator, factory_data->globals->id_generate, 1, self);
314
+ result = rb_funcall(wkb_generator, rb_intern("generate"), 1, self);
314
315
  }
315
316
  else {
316
317
  wkb_writer = factory_data->wkb_writer;
@@ -863,24 +864,21 @@ static VALUE method_geometry_union(VALUE self, VALUE rhs)
863
864
 
864
865
  static VALUE method_geometry_unary_union(VALUE self)
865
866
  {
866
- VALUE result;
867
+ #ifdef RGEO_GEOS_SUPPORTS_UNARYUNION
867
868
  RGeo_GeometryData* self_data;
868
869
  const GEOSGeometry* self_geom;
869
870
 
870
- result = Qnil;
871
-
872
- #ifdef RGEO_GEOS_SUPPORTS_UNARYUNION
873
871
  self_data = RGEO_GEOMETRY_DATA_PTR(self);
874
872
  self_geom = self_data->geom;
875
873
  if (self_geom) {
876
874
  GEOSContextHandle_t self_context = self_data->geos_context;
877
- result = rgeo_wrap_geos_geometry(self_data->factory,
875
+ return rgeo_wrap_geos_geometry(self_data->factory,
878
876
  GEOSUnaryUnion_r(self_context, self_geom),
879
877
  Qnil);
880
878
  }
881
879
  #endif
882
880
 
883
- return result;
881
+ return Qnil;
884
882
  }
885
883
 
886
884
 
@@ -1044,18 +1042,39 @@ static VALUE method_geometry_invalid_reason(VALUE self)
1044
1042
  self_data = RGEO_GEOMETRY_DATA_PTR(self);
1045
1043
  self_geom = self_data->geom;
1046
1044
  if (self_geom) {
1047
- str = GEOSisValidReason_r(self_data->geos_context, self_geom);
1048
- // Per documentation, a valid geometry should give an empty string.
1049
- // However it seems not to be the case. Hence the comparison against
1050
- // the string that is really given: `"Valid Geometry"`.
1051
- // See https://github.com/libgeos/geos/issues/431.
1052
- if (str) result = (str[0] == '\0' || !strcmp(str, "Valid Geometry")) ? Qnil : rb_str_new2(str);
1053
- else result = rb_str_new2("Exception");
1054
- GEOSFree_r(self_data->geos_context, str);
1045
+ // We use NULL there to tell GEOS that we don't care about the position.
1046
+ switch(GEOSisValidDetail_r(self_data->geos_context, self_geom, 0, &str, NULL)) {
1047
+ case 0: // invalid
1048
+ result = rb_utf8_str_new_cstr(str);
1049
+ case 1: // valid
1050
+ break;
1051
+ case 2: // exception
1052
+ default:
1053
+ result = rb_utf8_str_new_cstr("Exception");
1054
+ break;
1055
+ };
1056
+ if (str) GEOSFree_r(self_data->geos_context, str);
1055
1057
  }
1056
1058
  return result;
1057
1059
  }
1058
1060
 
1061
+ static VALUE method_geometry_make_valid(VALUE self)
1062
+ {
1063
+ RGeo_GeometryData* self_data;
1064
+ const GEOSGeometry* self_geom;
1065
+ GEOSGeometry* valid_geom;
1066
+ self_data = RGEO_GEOMETRY_DATA_PTR(self);
1067
+ self_geom = self_data->geom;
1068
+ if (!self_geom) return Qnil;
1069
+
1070
+ // According to GEOS implementation, MakeValid always returns.
1071
+ valid_geom = GEOSMakeValid_r(self_data->geos_context, self_geom);
1072
+ if (!valid_geom) {
1073
+ rb_raise(rb_eRGeoInvalidGeometry, "%"PRIsVALUE, method_geometry_invalid_reason(self));
1074
+ }
1075
+ return rgeo_wrap_geos_geometry(self_data->factory, valid_geom, Qnil);
1076
+ }
1077
+
1059
1078
  static VALUE method_geometry_point_on_surface(VALUE self)
1060
1079
  {
1061
1080
  VALUE result;
@@ -1071,15 +1090,27 @@ static VALUE method_geometry_point_on_surface(VALUE self)
1071
1090
  return result;
1072
1091
  }
1073
1092
 
1093
+ VALUE rgeo_geos_geometries_strict_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2)
1094
+ {
1095
+ switch (GEOSEqualsExact_r(context, geom1, geom2, 0.0)) {
1096
+ case 0:
1097
+ return Qfalse;
1098
+ case 1:
1099
+ return Qtrue;
1100
+ case 2:
1101
+ default:
1102
+ rb_raise(rb_eGeosError, "Cannot test equality.");
1103
+ }
1104
+ }
1074
1105
 
1075
1106
  /**** INITIALIZATION FUNCTION ****/
1076
1107
 
1077
1108
 
1078
- void rgeo_init_geos_geometry(RGeo_Globals* globals)
1109
+ void rgeo_init_geos_geometry()
1079
1110
  {
1080
1111
  VALUE geos_geometry_methods;
1081
1112
 
1082
- geos_geometry_methods = rb_define_module_under(globals->geos_module, "CAPIGeometryMethods");
1113
+ geos_geometry_methods = rb_define_module_under(rgeo_geos_module, "CAPIGeometryMethods");
1083
1114
 
1084
1115
  rb_define_method(geos_geometry_methods, "factory=", method_geometry_set_factory, 1);
1085
1116
  rb_define_method(geos_geometry_methods, "initialize_copy", method_geometry_initialize_copy, 1);
@@ -1095,8 +1126,8 @@ void rgeo_init_geos_geometry(RGeo_Globals* globals)
1095
1126
  rb_define_method(geos_geometry_methods, "boundary", method_geometry_boundary, 0);
1096
1127
  rb_define_method(geos_geometry_methods, "_as_text", method_geometry_as_text, 0);
1097
1128
  rb_define_method(geos_geometry_methods, "as_binary", method_geometry_as_binary, 0);
1098
- rb_define_method(geos_geometry_methods, "is_empty?", method_geometry_is_empty, 0);
1099
- rb_define_method(geos_geometry_methods, "is_simple?", method_geometry_is_simple, 0);
1129
+ rb_define_method(geos_geometry_methods, "empty?", method_geometry_is_empty, 0);
1130
+ rb_define_method(geos_geometry_methods, "simple?", method_geometry_is_simple, 0);
1100
1131
  rb_define_method(geos_geometry_methods, "equals?", method_geometry_equals, 1);
1101
1132
  rb_define_method(geos_geometry_methods, "==", method_geometry_equals, 1);
1102
1133
  rb_define_method(geos_geometry_methods, "rep_equals?", method_geometry_eql, 1);
@@ -1126,6 +1157,7 @@ void rgeo_init_geos_geometry(RGeo_Globals* globals)
1126
1157
  rb_define_method(geos_geometry_methods, "valid?", method_geometry_is_valid, 0);
1127
1158
  rb_define_method(geos_geometry_methods, "invalid_reason", method_geometry_invalid_reason, 0);
1128
1159
  rb_define_method(geos_geometry_methods, "point_on_surface", method_geometry_point_on_surface, 0);
1160
+ rb_define_method(geos_geometry_methods, "make_valid", method_geometry_make_valid, 0);
1129
1161
  }
1130
1162
 
1131
1163
 
@@ -6,8 +6,6 @@
6
6
  #ifndef RGEO_GEOS_GEOMETRY_INCLUDED
7
7
  #define RGEO_GEOS_GEOMETRY_INCLUDED
8
8
 
9
- #include "factory.h"
10
-
11
9
  RGEO_BEGIN_C
12
10
 
13
11
 
@@ -15,8 +13,15 @@ RGEO_BEGIN_C
15
13
  Initializes the geometry module. This should be called after the factory
16
14
  module is initialized, but before any of the other modules.
17
15
  */
18
- void rgeo_init_geos_geometry(RGeo_Globals* globals);
16
+ void rgeo_init_geos_geometry();
17
+
19
18
 
19
+ /*
20
+ Compares two geometries using strict GEOS comparison. return Qtrue
21
+ if they are equal, Qfalse otherwise.
22
+ May raise a `RGeo::Error::GeosError`.
23
+ */
24
+ VALUE rgeo_geos_geometries_strict_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2);
20
25
 
21
26
  RGEO_END_C
22
27