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.
- 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
|
[![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%
|
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/
|
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
|