rgeo 2.4.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.
- 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;
|