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.
- checksums.yaml +4 -4
- data/README.md +11 -11
- data/ext/geos_c_impl/factory.c +31 -30
- data/ext/geos_c_impl/factory.h +8 -1
- data/ext/geos_c_impl/geometry.c +70 -0
- data/ext/geos_c_impl/geometry_collection.c +43 -40
- data/ext/geos_c_impl/line_string.c +2 -2
- data/ext/geos_c_impl/main.c +1 -1
- data/ext/geos_c_impl/polygon.c +29 -22
- data/ext/geos_c_impl/preface.h +4 -0
- data/ext/geos_c_impl/ruby_more.c +65 -0
- data/ext/geos_c_impl/ruby_more.h +16 -0
- data/lib/rgeo/cartesian/factory.rb +6 -7
- data/lib/rgeo/cartesian/feature_classes.rb +2 -0
- data/lib/rgeo/cartesian/feature_methods.rb +16 -0
- data/lib/rgeo/cartesian/interface.rb +0 -30
- data/lib/rgeo/coord_sys.rb +0 -11
- data/lib/rgeo/feature/factory_generator.rb +0 -3
- data/lib/rgeo/feature/geometry.rb +79 -0
- data/lib/rgeo/geographic/factory.rb +6 -0
- data/lib/rgeo/geographic/interface.rb +1 -29
- data/lib/rgeo/geographic/projected_feature_methods.rb +16 -0
- data/lib/rgeo/geographic/spherical_feature_methods.rb +17 -1
- data/lib/rgeo/geos/capi_factory.rb +0 -7
- data/lib/rgeo/geos/capi_feature_classes.rb +19 -0
- data/lib/rgeo/geos/ffi_factory.rb +6 -7
- data/lib/rgeo/geos/ffi_feature_methods.rb +16 -0
- data/lib/rgeo/geos/interface.rb +0 -17
- data/lib/rgeo/geos/zm_factory.rb +0 -7
- data/lib/rgeo/geos/zm_feature_methods.rb +16 -0
- data/lib/rgeo/geos.rb +6 -3
- data/lib/rgeo/impl_helper/validity_check.rb +3 -2
- data/lib/rgeo/version.rb +1 -1
- metadata +18 -5
- data/lib/rgeo/coord_sys/srs_database/entry.rb +0 -107
- data/lib/rgeo/coord_sys/srs_database/sr_org.rb +0 -64
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 939fdbb8c9bbcb94342b99f952ad5524cb436683ea054bcab0aaa408f362ac2a
|
4
|
+
data.tar.gz: 4cd0c59ee3e08947c646c1b7e5c9a9755c44a0a87459437754867bbb5c2e304e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6f02199e30b35334156d3a1107213b6dab9028572e423d2f0f6072a7a2032586e26dfa5a594a8132b33d4071f0d55f6bd75dcd60d1e5a60df4bde0c51b7a78f
|
7
|
+
data.tar.gz: 20404c7de6aec61e04eae659253ddf16f518afce40c64274d261acc1a160f5420866c8188fed18425e1a55788e5041ff9b7a93c653f61cdde0a7ce15dccfa1a1
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
## RGeo
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/rgeo)
|
4
|
-
[](https://github.com/rgeo/rgeo/actions?query=workflow%3ACI+branch%
|
4
|
+
[](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/
|
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/
|
128
|
-
- [Enable GEOS and Proj4 on Heroku](https://github.com/rgeo/rgeo/blob/
|
129
|
-
- [Installing GEOS](https://github.com/rgeo/rgeo/blob/
|
130
|
-
- [Factory Compatibility](https://github.com/rgeo/rgeo/blob/
|
131
|
-
- [Which factory should I use?](https://github.com/rgeo/rgeo/blob/
|
132
|
-
- [Geometry validity handling](https://github.com/rgeo/rgeo/blob/
|
133
|
-
- [Examples](https://github.com/rgeo/rgeo/blob/
|
134
|
-
- [Who uses `rgeo`?](https://github.com/rgeo/rgeo/blob/
|
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/
|
161
|
+
[License](https://github.com/rgeo/rgeo/blob/main/LICENSE.txt)
|
data/ext/geos_c_impl/factory.c
CHANGED
@@ -13,15 +13,15 @@
|
|
13
13
|
#include <stdarg.h>
|
14
14
|
#include <stdio.h>
|
15
15
|
|
16
|
-
#include "
|
17
|
-
|
16
|
+
#include "errors.h"
|
18
17
|
#include "factory.h"
|
18
|
+
#include "globals.h"
|
19
19
|
#include "geometry.h"
|
20
|
-
#include "
|
20
|
+
#include "geometry_collection.h"
|
21
21
|
#include "line_string.h"
|
22
|
+
#include "point.h"
|
22
23
|
#include "polygon.h"
|
23
|
-
#include "
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
875
|
-
|
876
|
-
if (
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
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
|
|
data/ext/geos_c_impl/factory.h
CHANGED
@@ -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,
|
data/ext/geos_c_impl/geometry.c
CHANGED
@@ -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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
79
|
+
rb_ary_push(klasses, Qnil);
|
87
80
|
}
|
88
81
|
}
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
475
|
+
FREE(coords);
|
476
476
|
return coord_seq;
|
477
477
|
}
|
478
478
|
|
data/ext/geos_c_impl/main.c
CHANGED
data/ext/geos_c_impl/polygon.c
CHANGED
@@ -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 (
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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 (
|
262
|
-
|
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
|
-
|
269
|
-
|
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
|
-
|
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
|
|
data/ext/geos_c_impl/preface.h
CHANGED
@@ -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
|
|
@@ -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
|