rgeo 2.4.0 → 3.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +6 -0
- data/README.md +1 -0
- data/ext/geos_c_impl/analysis.c +4 -4
- data/ext/geos_c_impl/errors.c +8 -6
- data/ext/geos_c_impl/errors.h +7 -3
- data/ext/geos_c_impl/extconf.rb +2 -0
- data/ext/geos_c_impl/factory.c +80 -7
- data/ext/geos_c_impl/factory.h +28 -14
- data/ext/geos_c_impl/geometry.c +46 -14
- data/ext/geos_c_impl/geometry.h +7 -0
- data/ext/geos_c_impl/geometry_collection.c +2 -104
- data/ext/geos_c_impl/geometry_collection.h +0 -11
- data/ext/geos_c_impl/line_string.c +1 -1
- data/ext/geos_c_impl/point.c +1 -1
- data/ext/geos_c_impl/polygon.c +1 -37
- data/ext/geos_c_impl/preface.h +3 -0
- data/lib/rgeo/cartesian/calculations.rb +54 -17
- data/lib/rgeo/cartesian/factory.rb +0 -7
- data/lib/rgeo/cartesian/feature_classes.rb +66 -46
- data/lib/rgeo/cartesian/feature_methods.rb +51 -20
- data/lib/rgeo/cartesian/interface.rb +0 -6
- data/lib/rgeo/cartesian/planar_graph.rb +379 -0
- data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
- data/lib/rgeo/cartesian/valid_op.rb +71 -0
- data/lib/rgeo/cartesian.rb +3 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
- data/lib/rgeo/error.rb +15 -0
- data/lib/rgeo/feature/geometry.rb +28 -28
- data/lib/rgeo/feature/geometry_collection.rb +13 -5
- data/lib/rgeo/feature/line_string.rb +3 -3
- data/lib/rgeo/feature/multi_surface.rb +3 -3
- data/lib/rgeo/feature/point.rb +4 -4
- data/lib/rgeo/feature/surface.rb +3 -3
- data/lib/rgeo/geographic/factory.rb +0 -7
- data/lib/rgeo/geographic/interface.rb +5 -20
- data/lib/rgeo/geographic/proj4_projector.rb +0 -2
- data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
- data/lib/rgeo/geographic/projected_feature_methods.rb +51 -28
- data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
- data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
- data/lib/rgeo/geographic/spherical_feature_methods.rb +62 -1
- data/lib/rgeo/geos/capi_factory.rb +21 -31
- data/lib/rgeo/geos/capi_feature_classes.rb +35 -11
- data/lib/rgeo/geos/ffi_factory.rb +0 -28
- data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
- data/lib/rgeo/geos/ffi_feature_methods.rb +23 -5
- data/lib/rgeo/geos/interface.rb +0 -7
- data/lib/rgeo/geos/zm_factory.rb +0 -12
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +15 -19
- data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +1 -1
- data/lib/rgeo/impl_helper/valid_op.rb +354 -0
- data/lib/rgeo/impl_helper/validity_check.rb +138 -0
- data/lib/rgeo/impl_helper.rb +1 -0
- data/lib/rgeo/version.rb +1 -1
- metadata +31 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e26b01fb2fff6915756d98e206ee4bdabefeaceadae3cd0b85cb7be9ee6d8285
|
4
|
+
data.tar.gz: 9b94dd4e6c57e9fa5ab07c7b5fb9c622a52d843b67d146b52454933cb817a4a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9adb8cc283c8663fb0a178eeb7a1629fe466265f7fa15c54d4e8dac4188646a2682f591a3e76d12271df5dc6c875961833600b88952d035f824933bd454211de
|
7
|
+
data.tar.gz: c1f7e26d5a5edcc060cac2efaa782a586c9ee95e1dda08f7af771648ecc1ea2373a1e4ba9053aae00288332e401370c7f61e254367231ceabb4fb36ad5406209
|
data/.yardopts
ADDED
data/README.md
CHANGED
@@ -129,6 +129,7 @@ Here's the current list of available topics:
|
|
129
129
|
- [Installing GEOS](https://github.com/rgeo/rgeo/blob/master/doc/Installing-GEOS.md)
|
130
130
|
- [Factory Compatibility](https://github.com/rgeo/rgeo/blob/master/doc/Factory-Compatibility.md)
|
131
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)
|
132
133
|
- [Examples](https://github.com/rgeo/rgeo/blob/master/doc/Examples.md)
|
133
134
|
- [Who uses `rgeo`?](https://github.com/rgeo/rgeo/blob/master/doc/Gallery.md)
|
134
135
|
|
data/ext/geos_c_impl/analysis.c
CHANGED
@@ -37,9 +37,9 @@ VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring)
|
|
37
37
|
ring_data = RGEO_GEOMETRY_DATA_PTR(ring);
|
38
38
|
|
39
39
|
coord_seq = GEOSGeom_getCoordSeq_r(ring_data->geos_context, ring_data->geom);
|
40
|
-
if (!coord_seq) { rb_raise(
|
40
|
+
if (!coord_seq) { rb_raise(rb_eGeosError, "Could not retrieve CoordSeq from given ring."); }
|
41
41
|
if (!GEOSCoordSeq_isCCW_r(ring_data->geos_context, coord_seq, &is_ccw)) {
|
42
|
-
rb_raise(
|
42
|
+
rb_raise(rb_eGeosError, "Could not determine if the CoordSeq is CCW.");
|
43
43
|
}
|
44
44
|
|
45
45
|
return is_ccw ? Qtrue : Qfalse;
|
@@ -49,8 +49,8 @@ VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring)
|
|
49
49
|
|
50
50
|
/**
|
51
51
|
* call-seq:
|
52
|
-
* RGeo::Geos::Analysis.ccw_supported? -> true or false
|
53
|
-
*
|
52
|
+
* RGeo::Geos::Analysis.ccw_supported? -> true or false
|
53
|
+
*
|
54
54
|
* Checks if the RGEO_GEOS_SUPPORTS_ISCCW macro is defined, returns +true+
|
55
55
|
* if it is, +false+ otherwise
|
56
56
|
*/
|
data/ext/geos_c_impl/errors.c
CHANGED
@@ -14,18 +14,20 @@
|
|
14
14
|
|
15
15
|
RGEO_BEGIN_C
|
16
16
|
|
17
|
-
|
18
|
-
VALUE
|
19
|
-
|
20
|
-
VALUE
|
17
|
+
VALUE rb_eRGeoError;
|
18
|
+
VALUE rb_eRGeoInvalidGeometry;
|
19
|
+
VALUE rb_eRGeoUnsupportedOperation;
|
20
|
+
VALUE rb_eGeosError;
|
21
21
|
|
22
22
|
|
23
23
|
void rgeo_init_geos_errors() {
|
24
24
|
VALUE error_module;
|
25
25
|
|
26
26
|
error_module = rb_define_module_under(rgeo_module, "Error");
|
27
|
-
|
28
|
-
|
27
|
+
rb_eRGeoError = rb_define_class_under(error_module, "RGeoError", rb_eRuntimeError);
|
28
|
+
rb_eRGeoInvalidGeometry = rb_define_class_under(error_module, "InvalidGeometry", rb_eRGeoError);
|
29
|
+
rb_eRGeoUnsupportedOperation = rb_define_class_under(error_module, "UnsupportedOperation", rb_eRGeoError);
|
30
|
+
rb_eGeosError = rb_define_class_under(error_module, "GeosError", rb_eRGeoError);
|
29
31
|
}
|
30
32
|
|
31
33
|
RGEO_END_C
|
data/ext/geos_c_impl/errors.h
CHANGED
@@ -8,10 +8,14 @@
|
|
8
8
|
|
9
9
|
RGEO_BEGIN_C
|
10
10
|
|
11
|
-
//
|
12
|
-
extern VALUE
|
11
|
+
// Main rgeo error type
|
12
|
+
extern VALUE rb_eRGeoError;
|
13
|
+
// RGeo::Error::InvalidGeometry
|
14
|
+
extern VALUE rb_eRGeoInvalidGeometry;
|
15
|
+
// RGeo::Error::UnsupportedOperation
|
16
|
+
extern VALUE rb_eRGeoUnsupportedOperation;
|
13
17
|
// RGeo error specific to the GEOS implementation.
|
14
|
-
extern VALUE
|
18
|
+
extern VALUE rb_eGeosError;
|
15
19
|
|
16
20
|
void rgeo_init_geos_errors();
|
17
21
|
|
data/ext/geos_c_impl/extconf.rb
CHANGED
data/ext/geos_c_impl/factory.c
CHANGED
@@ -9,6 +9,9 @@
|
|
9
9
|
|
10
10
|
#include <ruby.h>
|
11
11
|
#include <geos_c.h>
|
12
|
+
#include <ctype.h>
|
13
|
+
#include <stdarg.h>
|
14
|
+
#include <stdio.h>
|
12
15
|
|
13
16
|
#include "globals.h"
|
14
17
|
|
@@ -26,13 +29,50 @@ RGEO_BEGIN_C
|
|
26
29
|
/**** RUBY AND GEOS CALLBACKS ****/
|
27
30
|
|
28
31
|
|
29
|
-
//
|
30
|
-
// for
|
31
|
-
|
32
|
-
|
32
|
+
// The notice handler is very rarely used by GEOS, only in
|
33
|
+
// GEOSIsValid_r (check for NOTICE_MESSAGE in GEOS codebase).
|
34
|
+
// We still set it to make sure we do not miss any implementation
|
35
|
+
// change. Use `DEBUG=1 rake` to show notice.
|
36
|
+
#ifdef RGEO_GEOS_DEBUG
|
37
|
+
static void notice_handler(const char* fmt, ...)
|
33
38
|
{
|
39
|
+
va_list args;
|
40
|
+
va_start(args, fmt);
|
41
|
+
fprintf(stderr, "GEOS Notice -- ");
|
42
|
+
vfprintf(stderr, fmt, args);
|
43
|
+
fprintf(stderr, "\n");
|
44
|
+
va_end(args);
|
34
45
|
}
|
46
|
+
#endif
|
35
47
|
|
48
|
+
static void error_handler(const char* fmt, ...)
|
49
|
+
{
|
50
|
+
// See https://en.cppreference.com/w/c/io/vfprintf
|
51
|
+
va_list args1;
|
52
|
+
va_start(args1, fmt);
|
53
|
+
va_list args2;
|
54
|
+
va_copy(args2, args1);
|
55
|
+
int size = 1+vsnprintf(NULL, 0, fmt, args1);
|
56
|
+
va_end(args1);
|
57
|
+
char geos_full_error[size];
|
58
|
+
vsnprintf(geos_full_error, sizeof geos_full_error, fmt, args2);
|
59
|
+
va_end(args2);
|
60
|
+
|
61
|
+
// NOTE: strtok is destructive, geos_full_error is not to be used afterwards.
|
62
|
+
char *geos_error = strtok(geos_full_error, ":");
|
63
|
+
char *geos_message = strtok(NULL, ":");
|
64
|
+
while(isspace(*geos_message)) geos_message++;
|
65
|
+
|
66
|
+
if (streq(geos_error, "UnsupportedOperationException")) {
|
67
|
+
rb_raise(rb_eRGeoUnsupportedOperation, "%s", geos_message);
|
68
|
+
} else if (streq(geos_error, "IllegalArgumentException")) {
|
69
|
+
rb_raise(rb_eRGeoInvalidGeometry, "%s", geos_message);
|
70
|
+
} else if (geos_message) {
|
71
|
+
rb_raise(rb_eGeosError, "%s: %s", geos_error, geos_message);
|
72
|
+
} else {
|
73
|
+
rb_raise(rb_eGeosError, "%s", geos_error);
|
74
|
+
}
|
75
|
+
}
|
36
76
|
|
37
77
|
// Destroy function for factory data. We destroy any serialization
|
38
78
|
// objects that have been created for the factory, and then destroy
|
@@ -227,6 +267,25 @@ static VALUE method_factory_flags(VALUE self)
|
|
227
267
|
return INT2NUM(RGEO_FACTORY_DATA_PTR(self)->flags);
|
228
268
|
}
|
229
269
|
|
270
|
+
VALUE method_factory_supports_z_p(VALUE self)
|
271
|
+
{
|
272
|
+
return RGEO_FACTORY_DATA_PTR(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z ? Qtrue : Qfalse;
|
273
|
+
}
|
274
|
+
|
275
|
+
VALUE method_factory_supports_m_p(VALUE self)
|
276
|
+
{
|
277
|
+
return RGEO_FACTORY_DATA_PTR(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_M ? Qtrue : Qfalse;
|
278
|
+
}
|
279
|
+
|
280
|
+
VALUE method_factory_supports_z_or_m_p(VALUE self)
|
281
|
+
{
|
282
|
+
return RGEO_FACTORY_DATA_PTR(self)->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M ? Qtrue : Qfalse;
|
283
|
+
}
|
284
|
+
|
285
|
+
VALUE method_factory_prepare_heuristic_p(VALUE self)
|
286
|
+
{
|
287
|
+
return RGEO_FACTORY_DATA_PTR(self)->flags & RGEO_FACTORYFLAGS_PREPARE_HEURISTIC ? Qtrue : Qfalse;
|
288
|
+
}
|
230
289
|
|
231
290
|
static VALUE method_factory_parse_wkt(VALUE self, VALUE str)
|
232
291
|
{
|
@@ -459,7 +518,12 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
|
|
459
518
|
result = Qnil;
|
460
519
|
data = ALLOC(RGeo_FactoryData);
|
461
520
|
if (data) {
|
462
|
-
context =
|
521
|
+
context = GEOS_init_r();
|
522
|
+
#ifdef RGEO_GEOS_DEBUG
|
523
|
+
GEOSContext_setNoticeHandler_r(context, notice_handler);
|
524
|
+
#endif
|
525
|
+
GEOSContext_setErrorHandler_r(context, error_handler);
|
526
|
+
|
463
527
|
if (context) {
|
464
528
|
data->geos_context = context;
|
465
529
|
data->flags = NUM2INT(flags);
|
@@ -629,15 +693,24 @@ void rgeo_init_geos_factory()
|
|
629
693
|
rb_gc_register_address(&marshal_wkb_generator);
|
630
694
|
#endif
|
631
695
|
|
632
|
-
// Add C methods to the factory.
|
633
696
|
geos_factory_class = rb_define_class_under(rgeo_geos_module, "CAPIFactory", rb_cObject);
|
634
697
|
rb_define_alloc_func(geos_factory_class, alloc_factory);
|
698
|
+
// Add C constants to the factory.
|
699
|
+
rb_define_const(geos_factory_class, "FLAG_SUPPORTS_Z", INT2FIX(RGEO_FACTORYFLAGS_SUPPORTS_Z));
|
700
|
+
rb_define_const(geos_factory_class, "FLAG_SUPPORTS_M", INT2FIX(RGEO_FACTORYFLAGS_SUPPORTS_M));
|
701
|
+
rb_define_const(geos_factory_class, "FLAG_SUPPORTS_Z_OR_M", INT2FIX(RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M));
|
702
|
+
rb_define_const(geos_factory_class, "FLAG_PREPARE_HEURISTIC", INT2FIX(RGEO_FACTORYFLAGS_PREPARE_HEURISTIC));
|
703
|
+
// Add C methods to the factory.
|
635
704
|
rb_define_method(geos_factory_class, "initialize_copy", method_factory_initialize_copy, 1);
|
636
705
|
rb_define_method(geos_factory_class, "_parse_wkt_impl", method_factory_parse_wkt, 1);
|
637
706
|
rb_define_method(geos_factory_class, "_parse_wkb_impl", method_factory_parse_wkb, 1);
|
638
707
|
rb_define_method(geos_factory_class, "_srid", method_factory_srid, 0);
|
639
708
|
rb_define_method(geos_factory_class, "_buffer_resolution", method_factory_buffer_resolution, 0);
|
640
709
|
rb_define_method(geos_factory_class, "_flags", method_factory_flags, 0);
|
710
|
+
rb_define_method(geos_factory_class, "supports_z?", method_factory_supports_z_p, 0);
|
711
|
+
rb_define_method(geos_factory_class, "supports_m?", method_factory_supports_m_p, 0);
|
712
|
+
rb_define_method(geos_factory_class, "supports_z_or_m?", method_factory_supports_z_or_m_p, 0);
|
713
|
+
rb_define_method(geos_factory_class, "prepare_heuristic?", method_factory_prepare_heuristic_p, 0);
|
641
714
|
rb_define_method(geos_factory_class, "_set_wkrep_parsers", method_set_wkrep_parsers, 2);
|
642
715
|
rb_define_method(geos_factory_class, "_proj4", method_get_proj4, 0);
|
643
716
|
rb_define_method(geos_factory_class, "_coord_sys", method_get_coord_sys, 0);
|
@@ -831,7 +904,7 @@ char rgeo_is_geos_object(VALUE obj)
|
|
831
904
|
void rgeo_check_geos_object(VALUE obj)
|
832
905
|
{
|
833
906
|
if (!rgeo_is_geos_object(obj)) {
|
834
|
-
rb_raise(
|
907
|
+
rb_raise(rb_eRGeoError, "Not a GEOS Geometry object.");
|
835
908
|
}
|
836
909
|
}
|
837
910
|
|
data/ext/geos_c_impl/factory.h
CHANGED
@@ -37,12 +37,35 @@ typedef struct {
|
|
37
37
|
int buffer_resolution;
|
38
38
|
} RGeo_FactoryData;
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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);
|
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);
|
45
64
|
|
65
|
+
/* call-seq:
|
66
|
+
* RGeo::Geos::CAPIFactory.prepare_heuristic? -> true or false
|
67
|
+
*/
|
68
|
+
VALUE method_factory_prepare_heuristic_p(VALUE self);
|
46
69
|
|
47
70
|
/*
|
48
71
|
Wrapped structure for Geometry objects.
|
@@ -164,15 +187,6 @@ void rgeo_check_geos_object(VALUE obj);
|
|
164
187
|
*/
|
165
188
|
const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj);
|
166
189
|
|
167
|
-
/*
|
168
|
-
Compares the coordinate sequences for two given GEOS geometries.
|
169
|
-
The two given geometries MUST be of types backed directly by
|
170
|
-
coordinate sequences-- i.e. points or line strings.
|
171
|
-
Returns Qtrue if the two coordinate sequences are equal, Qfalse
|
172
|
-
if they are inequal, or Qnil if an error occurs.
|
173
|
-
*/
|
174
|
-
VALUE rgeo_geos_coordseqs_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
|
175
|
-
|
176
190
|
/*
|
177
191
|
Compares the ruby classes and geometry factories of the two given ruby
|
178
192
|
objects. Returns Qtrue if everything is equal (that is, the two objects
|
data/ext/geos_c_impl/geometry.c
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
|
14
14
|
#include "globals.h"
|
15
15
|
|
16
|
+
#include "errors.h"
|
16
17
|
#include "factory.h"
|
17
18
|
#include "geometry.h"
|
18
19
|
|
@@ -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
|
-
|
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
|
-
|
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
|
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
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
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,6 +1090,18 @@ 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
|
|
@@ -1126,6 +1157,7 @@ void rgeo_init_geos_geometry()
|
|
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
|
|
data/ext/geos_c_impl/geometry.h
CHANGED
@@ -16,6 +16,13 @@ RGEO_BEGIN_C
|
|
16
16
|
void rgeo_init_geos_geometry();
|
17
17
|
|
18
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);
|
25
|
+
|
19
26
|
RGEO_END_C
|
20
27
|
|
21
28
|
#endif
|
@@ -16,6 +16,7 @@
|
|
16
16
|
#include "geometry.h"
|
17
17
|
#include "line_string.h"
|
18
18
|
#include "polygon.h"
|
19
|
+
#include "geometry.h"
|
19
20
|
#include "geometry_collection.h"
|
20
21
|
|
21
22
|
#include "coordinates.h"
|
@@ -43,9 +44,6 @@ static VALUE create_geometry_collection(VALUE module, int type, VALUE factory, V
|
|
43
44
|
VALUE cast_type;
|
44
45
|
GEOSGeometry* geom;
|
45
46
|
GEOSGeometry* collection;
|
46
|
-
char problem;
|
47
|
-
GEOSGeometry* igeom;
|
48
|
-
GEOSGeometry* jgeom;
|
49
47
|
|
50
48
|
result = Qnil;
|
51
49
|
Check_Type(array, T_ARRAY);
|
@@ -90,32 +88,6 @@ static VALUE create_geometry_collection(VALUE module, int type, VALUE factory, V
|
|
90
88
|
}
|
91
89
|
else {
|
92
90
|
collection = GEOSGeom_createCollection_r(geos_context, type, geoms, len);
|
93
|
-
// Due to a limitation of GEOS, the MultiPolygon assertions are not checked.
|
94
|
-
// We do that manually here.
|
95
|
-
if (collection && type == GEOS_MULTIPOLYGON && (factory_data->flags & 1) == 0) {
|
96
|
-
problem = 0;
|
97
|
-
for (i=1; i<len; ++i) {
|
98
|
-
for (j=0; j<i; ++j) {
|
99
|
-
igeom = geoms[i];
|
100
|
-
jgeom = geoms[j];
|
101
|
-
problem = GEOSRelatePattern_r(geos_context, igeom, jgeom, "2********");
|
102
|
-
if (problem) {
|
103
|
-
break;
|
104
|
-
}
|
105
|
-
problem = GEOSRelatePattern_r(geos_context, igeom, jgeom, "****1****");
|
106
|
-
if (problem) {
|
107
|
-
break;
|
108
|
-
}
|
109
|
-
}
|
110
|
-
if (problem) {
|
111
|
-
break;
|
112
|
-
}
|
113
|
-
}
|
114
|
-
if (problem) {
|
115
|
-
GEOSGeom_destroy_r(geos_context, collection);
|
116
|
-
collection = NULL;
|
117
|
-
}
|
118
|
-
}
|
119
91
|
if (collection) {
|
120
92
|
result = rgeo_wrap_geos_geometry(factory, collection, module);
|
121
93
|
RGEO_GEOMETRY_DATA_PTR(result)->klasses = klasses;
|
@@ -143,7 +115,7 @@ static VALUE method_geometry_collection_eql(VALUE self, VALUE rhs)
|
|
143
115
|
result = rgeo_geos_klasses_and_factories_eql(self, rhs);
|
144
116
|
if (RTEST(result)) {
|
145
117
|
self_data = RGEO_GEOMETRY_DATA_PTR(self);
|
146
|
-
result =
|
118
|
+
result = rgeo_geos_geometries_strict_eql(self_data->geos_context, self_data->geom, RGEO_GEOMETRY_DATA_PTR(rhs)->geom);
|
147
119
|
}
|
148
120
|
return result;
|
149
121
|
}
|
@@ -635,80 +607,6 @@ void rgeo_init_geos_geometry_collection()
|
|
635
607
|
/**** OTHER PUBLIC FUNCTIONS ****/
|
636
608
|
|
637
609
|
|
638
|
-
VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
|
639
|
-
{
|
640
|
-
VALUE result;
|
641
|
-
int len1;
|
642
|
-
int len2;
|
643
|
-
int i;
|
644
|
-
const GEOSGeometry* sub_geom1;
|
645
|
-
const GEOSGeometry* sub_geom2;
|
646
|
-
int type1;
|
647
|
-
int type2;
|
648
|
-
|
649
|
-
result = Qnil;
|
650
|
-
if (geom1 && geom2) {
|
651
|
-
len1 = GEOSGetNumGeometries_r(context, geom1);
|
652
|
-
len2 = GEOSGetNumGeometries_r(context, geom2);
|
653
|
-
if (len1 >= 0 && len2 >= 0) {
|
654
|
-
if (len1 == len2) {
|
655
|
-
result = Qtrue;
|
656
|
-
for (i=0; i<len1; ++i) {
|
657
|
-
sub_geom1 = GEOSGetGeometryN_r(context, geom1, i);
|
658
|
-
sub_geom2 = GEOSGetGeometryN_r(context, geom2, i);
|
659
|
-
if (sub_geom1 && sub_geom2) {
|
660
|
-
type1 = GEOSGeomTypeId_r(context, sub_geom1);
|
661
|
-
type2 = GEOSGeomTypeId_r(context, sub_geom2);
|
662
|
-
if (type1 >= 0 && type2 >= 0) {
|
663
|
-
if (type1 == type2) {
|
664
|
-
switch (type1) {
|
665
|
-
case GEOS_POINT:
|
666
|
-
case GEOS_LINESTRING:
|
667
|
-
case GEOS_LINEARRING:
|
668
|
-
result = rgeo_geos_coordseqs_eql(context, sub_geom1, sub_geom2, check_z);
|
669
|
-
break;
|
670
|
-
case GEOS_POLYGON:
|
671
|
-
result = rgeo_geos_polygons_eql(context, sub_geom1, sub_geom2, check_z);
|
672
|
-
break;
|
673
|
-
case GEOS_GEOMETRYCOLLECTION:
|
674
|
-
case GEOS_MULTIPOINT:
|
675
|
-
case GEOS_MULTILINESTRING:
|
676
|
-
case GEOS_MULTIPOLYGON:
|
677
|
-
result = rgeo_geos_geometry_collections_eql(context, sub_geom1, sub_geom2, check_z);
|
678
|
-
break;
|
679
|
-
default:
|
680
|
-
result = Qnil;
|
681
|
-
break;
|
682
|
-
}
|
683
|
-
if (!RTEST(result)) {
|
684
|
-
break;
|
685
|
-
}
|
686
|
-
}
|
687
|
-
else {
|
688
|
-
result = Qfalse;
|
689
|
-
break;
|
690
|
-
}
|
691
|
-
}
|
692
|
-
else {
|
693
|
-
result = Qnil;
|
694
|
-
break;
|
695
|
-
}
|
696
|
-
}
|
697
|
-
else {
|
698
|
-
result = Qnil;
|
699
|
-
break;
|
700
|
-
}
|
701
|
-
}
|
702
|
-
}
|
703
|
-
else {
|
704
|
-
result = Qfalse;
|
705
|
-
}
|
706
|
-
}
|
707
|
-
}
|
708
|
-
return result;
|
709
|
-
}
|
710
|
-
|
711
|
-
|
712
610
|
st_index_t rgeo_geos_geometry_collection_hash(GEOSContextHandle_t context, const GEOSGeometry* geom, st_index_t hash)
|
713
611
|
{
|
714
612
|
const GEOSGeometry* sub_geom;
|
@@ -18,17 +18,6 @@ RGEO_BEGIN_C
|
|
18
18
|
*/
|
19
19
|
void rgeo_init_geos_geometry_collection();
|
20
20
|
|
21
|
-
/*
|
22
|
-
Comopares the contents of two geometry collections. Does not test the
|
23
|
-
types of the collections themselves, but tests the types, values, and
|
24
|
-
contents of all the contents. The two given geometries MUST be
|
25
|
-
collection types-- i.e. GeometryCollection, MultiPoint, MultiLineString,
|
26
|
-
or MultiPolygon.
|
27
|
-
Returns Qtrue if the contents of the two geometry collections are equal,
|
28
|
-
Qfalse if they are inequal, or Qnil if an error occurs.
|
29
|
-
*/
|
30
|
-
VALUE rgeo_geos_geometry_collections_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z);
|
31
|
-
|
32
21
|
/*
|
33
22
|
A tool for building up hash values.
|
34
23
|
You must pass in the context, a geos geometry, and a seed hash.
|
@@ -345,7 +345,7 @@ static VALUE method_line_string_eql(VALUE self, VALUE rhs)
|
|
345
345
|
result = rgeo_geos_klasses_and_factories_eql(self, rhs);
|
346
346
|
if (RTEST(result)) {
|
347
347
|
self_data = RGEO_GEOMETRY_DATA_PTR(self);
|
348
|
-
result =
|
348
|
+
result = rgeo_geos_geometries_strict_eql(self_data->geos_context, self_data->geom, RGEO_GEOMETRY_DATA_PTR(rhs)->geom);
|
349
349
|
}
|
350
350
|
return result;
|
351
351
|
}
|
data/ext/geos_c_impl/point.c
CHANGED
@@ -155,7 +155,7 @@ static VALUE method_point_eql(VALUE self, VALUE rhs)
|
|
155
155
|
result = rgeo_geos_klasses_and_factories_eql(self, rhs);
|
156
156
|
if (RTEST(result)) {
|
157
157
|
self_data = RGEO_GEOMETRY_DATA_PTR(self);
|
158
|
-
result =
|
158
|
+
result = rgeo_geos_geometries_strict_eql(self_data->geos_context, self_data->geom, RGEO_GEOMETRY_DATA_PTR(rhs)->geom);
|
159
159
|
}
|
160
160
|
return result;
|
161
161
|
}
|
data/ext/geos_c_impl/polygon.c
CHANGED
@@ -30,7 +30,7 @@ static VALUE method_polygon_eql(VALUE self, VALUE rhs)
|
|
30
30
|
result = rgeo_geos_klasses_and_factories_eql(self, rhs);
|
31
31
|
if (RTEST(result)) {
|
32
32
|
self_data = RGEO_GEOMETRY_DATA_PTR(self);
|
33
|
-
result =
|
33
|
+
result = rgeo_geos_geometries_strict_eql(self_data->geos_context, self_data->geom, RGEO_GEOMETRY_DATA_PTR(rhs)->geom);
|
34
34
|
}
|
35
35
|
return result;
|
36
36
|
}
|
@@ -299,42 +299,6 @@ void rgeo_init_geos_polygon()
|
|
299
299
|
rb_define_method(geos_polygon_methods, "coordinates", method_polygon_coordinates, 0);
|
300
300
|
}
|
301
301
|
|
302
|
-
|
303
|
-
VALUE rgeo_geos_polygons_eql(GEOSContextHandle_t context, const GEOSGeometry* geom1, const GEOSGeometry* geom2, char check_z)
|
304
|
-
{
|
305
|
-
VALUE result;
|
306
|
-
int len1;
|
307
|
-
int len2;
|
308
|
-
int i;
|
309
|
-
|
310
|
-
result = Qnil;
|
311
|
-
if (geom1 && geom2) {
|
312
|
-
result = rgeo_geos_coordseqs_eql(context, GEOSGetExteriorRing_r(context, geom1), GEOSGetExteriorRing_r(context, geom2), check_z);
|
313
|
-
if (RTEST(result)) {
|
314
|
-
len1 = GEOSGetNumInteriorRings_r(context, geom1);
|
315
|
-
len2 = GEOSGetNumInteriorRings_r(context, geom2);
|
316
|
-
if (len1 >= 0 && len2 >= 0) {
|
317
|
-
if (len1 == len2) {
|
318
|
-
for (i=0; i<len1; ++i) {
|
319
|
-
result = rgeo_geos_coordseqs_eql(context, GEOSGetInteriorRingN_r(context, geom1, i), GEOSGetInteriorRingN_r(context, geom2, i), check_z);
|
320
|
-
if (!RTEST(result)) {
|
321
|
-
break;
|
322
|
-
}
|
323
|
-
}
|
324
|
-
}
|
325
|
-
else {
|
326
|
-
result = Qfalse;
|
327
|
-
}
|
328
|
-
}
|
329
|
-
else {
|
330
|
-
result = Qnil;
|
331
|
-
}
|
332
|
-
}
|
333
|
-
}
|
334
|
-
return result;
|
335
|
-
}
|
336
|
-
|
337
|
-
|
338
302
|
st_index_t rgeo_geos_polygon_hash(GEOSContextHandle_t context, const GEOSGeometry* geom, st_index_t hash)
|
339
303
|
{
|
340
304
|
unsigned int len;
|