rgeo 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65bbadb93580fd02234007e3ddfb888b4a38b4a7dfaa2d2b0d072d313b98adfb
4
- data.tar.gz: b45a6f33bba7543ee86e0211a8b9d976cfef470222ab2adb9107f98b06818fff
3
+ metadata.gz: 0f0ded4953c3ad02eb5512ae8a9e8dd204e2008360678807a4ecea567c39533c
4
+ data.tar.gz: 577998a9cc566eba2146fb5a5e02e26db330e38f2b8518551b50c86fa8a7a027
5
5
  SHA512:
6
- metadata.gz: 33d2c278eb28f697047c98091676fae7161f3b410375ba8b5042f51cb5e10158c69617d044a19d1c68b86c399439fc6a22e3bf39d8767b303194f1d64b191d41
7
- data.tar.gz: 5e77a71cc569f9826fbac6d97ccd2aac46d2b7e37284cba950b6d8621ae04b52ed60c9a63bec7c5d227b3656e2015b1d3062eb1eaf15438de383209f1d6b291e
6
+ metadata.gz: 01f855c7553814054b662dbc9e84629f878ee71f642901cfb32f09386737cba9e0a86a2e91cbbe660515095d24cb09fb45d4b0ed680eac2f8194e0399eafe7c7
7
+ data.tar.gz: 810f5ef0b1b0f7c20d1a2b8845cdd443b9646aa564965d98d2b0d9b4bb25211e810cc73b780ff14e405dd824f5d7305a8a473a952e89e0f397406672f8fceab1
@@ -0,0 +1,144 @@
1
+ ## RGeo
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/rgeo.svg)](http://badge.fury.io/rb/rgeo)
4
+ [![Build Status](https://travis-ci.org/rgeo/rgeo.svg?branch=master)](https://travis-ci.org/rgeo/rgeo)
5
+
6
+ RGeo is a geospatial data library for Ruby.
7
+
8
+ :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning:
9
+
10
+ This organization is looking for maintainers, see [this issue](https://github.com/rgeo/rgeo/issues/216) for more information.
11
+
12
+ :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning:
13
+
14
+ ### Summary
15
+
16
+ RGeo is a key component for writing location-aware applications in the Ruby
17
+ programming language. At its core is an implementation of the industry
18
+ standard OGC Simple Features Specification, which provides data
19
+ representations of geometric objects such as points, lines, and polygons,
20
+ along with a set of geometric analysis operations. This makes it ideal for
21
+ modeling geolocation data. It also supports a suite of optional add-on modules
22
+ that provide various geolocation-related services.
23
+
24
+ Use the core **rgeo** gem to:
25
+
26
+ * Represent spatial and geolocation data objects such as points, lines, and
27
+ polygons in your Ruby application.
28
+ * Perform standard spatial analysis operations such as finding
29
+ intersections, creating buffers, and computing lengths and areas.
30
+ * Correctly handle spherical geometry, and compute geographic projections
31
+ for map display and data analysis.
32
+ * Read and write location data in the WKT and WKB representations used by
33
+ spatial databases.
34
+
35
+
36
+ ### Dependencies
37
+
38
+ RGeo works with the following Ruby implementations:
39
+
40
+ * MRI Ruby 2.3.0 or later.
41
+ * Partial support for JRuby 9.0 or later. The FFI implementation of GEOS
42
+ is available (ffi-geos gem required) but CAPI is not.
43
+ * See earlier versions for support for older ruby versions.
44
+
45
+ Some features also require the following:
46
+
47
+ * GEOS 3.2 or later is highly recommended. (3.3.3 or later preferred.) Some
48
+ functions will not be available without it. This C/C++ library may be
49
+ available via your operating system's package manager (`sudo aptitude
50
+ install libgeos-dev` for debian based Linux distributions, `yum install geos geos-devel` for redhat based Linux distributions), or you can
51
+ download it from http://trac.osgeo.org/geos
52
+ * On some platforms, you should install the ffi-geos gem (version 1.2.0 or
53
+ later recommended.) JRuby requires this gem to link properly with Geos,
54
+ and Windows builds probably do as well.
55
+
56
+ ### Installation
57
+
58
+ Install the RGeo gem:
59
+
60
+ ```sh
61
+ gem install rgeo
62
+ ```
63
+
64
+ or include it in your Gemfile:
65
+
66
+ ```ruby
67
+ gem "rgeo"
68
+ ```
69
+
70
+ If you are using proj.4 extensions, include
71
+ [`rgeo-proj4`](https://github.com/rgeo/rgeo-proj4):
72
+
73
+ ```ruby
74
+ gem "rgeo-proj4"
75
+ ```
76
+
77
+
78
+ ### Extensions
79
+
80
+ The [RGeo organization](https://github.com/rgeo) provides several gems that extend RGeo:
81
+
82
+ #### [`rgeo-proj4`](https://github.com/rgeo/rgeo-proj4)
83
+
84
+ Proj4 extensions
85
+
86
+ #### [`rgeo-geojson`](https://github.com/rgeo/rgeo-geojson)
87
+
88
+ Read and write GeoJSON
89
+
90
+ #### [`rgeo-shapefile`](https://github.com/rgeo/rgeo-shapefile)
91
+
92
+ Read ESRI shapefiles
93
+
94
+ #### [`activerecord-postgis-adapter`](https://github.com/rgeo/activerecord-postgis-adapter)
95
+
96
+ ActiveRecord connection adapter for PostGIS, based on postgresql (pg gem)
97
+
98
+ #### [`activerecord-mysql2spatial-adapter`](https://github.com/rgeo/activerecord-mysql2spatial-adapter)
99
+
100
+ ActiveRecord connection adapter for MySQL Spatial Extensions, based on mysql2
101
+
102
+ #### [`activerecord-spatialite-adapter`](https://github.com/rgeo/activerecord-spatialite-adapter)
103
+
104
+ ActiveRecord connection adapter for SpatiaLite, based on sqlite3 (*not maintained)
105
+
106
+
107
+ ### Development and support
108
+
109
+ RDoc Documentation is available at https://www.rubydoc.info/gems/rgeo
110
+
111
+ Contributions are welcome. Please read the
112
+ [Contributing guidelines](https://github.com/rgeo/rgeo/blob/master/CONTRIBUTING.md).
113
+
114
+ Support may be available on the
115
+ [rgeo-users google group](https://groups.google.com/forum/#!forum/rgeo-users)
116
+ or on [Stack Overflow](https://stackoverflow.com/questions/tagged/rgeo).
117
+
118
+
119
+ ### Acknowledgments
120
+
121
+ RGeo was created by [Daniel Azuma](http://www.daniel-azuma.com).
122
+ [Tee Parham](https://github.com/teeparham) is the current maintainer.
123
+
124
+ Thanks to [Pirq](http://www.pirq.com) and [Neighborland](https://neighborland.com)
125
+ for development support.
126
+
127
+ Thanks to [Travis-CI](https://travis-ci.org) for CI testing.
128
+
129
+ Thanks to [JetBrains](https://www.jetbrains.com/?from=rgeo) for RubyMine license.
130
+
131
+ RGeo calls the GEOS library to handle most Cartesian geometric calculations,
132
+ and the Proj4 library to handle projections and coordinate transformations.
133
+ These libraries are maintained by the Open Source Geospatial Foundation; more
134
+ information is available on [OSGeo's web site](http://www.osgeo.org).
135
+
136
+ JRuby support is made possible by the ffi-geos (and upcoming ffi-proj4) gems,
137
+ by [J Smith](https://github.com/dark-panda).
138
+
139
+
140
+ ### License
141
+
142
+ Copyright (c) Daniel Azuma, Tee Parham
143
+
144
+ [License](https://github.com/rgeo/rgeo/blob/master/LICENSE.txt)
@@ -0,0 +1,78 @@
1
+ /*
2
+ Analysis methos for GEOS wrapper
3
+ */
4
+
5
+ #include "preface.h"
6
+
7
+ #ifdef RGEO_GEOS_SUPPORTED
8
+
9
+ #include <ruby.h>
10
+ #include <geos_c.h>
11
+
12
+ #include "analysis.h"
13
+ #include "factory.h"
14
+ #include "errors.h"
15
+
16
+ RGEO_BEGIN_C
17
+
18
+ /*
19
+ * call-seq:
20
+ * RGeo::Geos::Analysis.ccw? -> true or false
21
+ *
22
+ * Checks direction for a ring, returns +true+ if counter-clockwise, +false+
23
+ * otherwise.
24
+ */
25
+ #ifdef RGEO_GEOS_SUPPORTS_ISCCW
26
+ VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring)
27
+ {
28
+
29
+ const RGeo_GeometryData* ring_data;
30
+ const GEOSCoordSequence* coord_seq;
31
+ char is_ccw;
32
+
33
+ rgeo_check_geos_object(ring);
34
+
35
+ ring_data = RGEO_GEOMETRY_DATA_PTR(ring);
36
+
37
+ coord_seq = GEOSGeom_getCoordSeq_r(ring_data->geos_context, ring_data->geom);
38
+ if (!coord_seq) { rb_raise(geos_error, "Could not retrieve CoordSeq from given ring."); }
39
+ if (!GEOSCoordSeq_isCCW_r(ring_data->geos_context, coord_seq, &is_ccw)) {
40
+ rb_raise(geos_error, "Could not determine if the CoordSeq is CCW.");
41
+ }
42
+
43
+ return is_ccw ? Qtrue : Qfalse;
44
+ };
45
+ #endif // RGEO_GEOS_SUPPORTS_ISCCW
46
+
47
+
48
+ /**
49
+ * call-seq:
50
+ * RGeo::Geos::Analysis.ccw_supported? -> true or false
51
+ *
52
+ * Checks if the RGEO_GEOS_SUPPORTS_ISCCW macro is defined, returns +true+
53
+ * if it is, +false+ otherwise
54
+ */
55
+ VALUE rgeo_geos_analysis_supports_ccw(VALUE self)
56
+ {
57
+ #ifdef RGEO_GEOS_SUPPORTS_ISCCW
58
+ return Qtrue;
59
+ #else
60
+ return Qfalse;
61
+ #endif
62
+ }
63
+
64
+
65
+ void rgeo_init_geos_analysis(RGeo_Globals* globals)
66
+ {
67
+ VALUE geos_analysis_module;
68
+
69
+ geos_analysis_module = rb_define_module_under(globals->geos_module, "Analysis");
70
+ rb_define_singleton_method(geos_analysis_module, "ccw_supported?", rgeo_geos_analysis_supports_ccw, 0);
71
+ #ifdef RGEO_GEOS_SUPPORTS_ISCCW
72
+ rb_define_singleton_method(geos_analysis_module, "ccw?", rgeo_geos_analysis_ccw_p, 1);
73
+ #endif // RGEO_GEOS_SUPPORTS_ISCCW
74
+ }
75
+
76
+ RGEO_END_C
77
+
78
+ #endif
@@ -0,0 +1,42 @@
1
+ /*
2
+ Analysis methos for GEOS wrapper
3
+ */
4
+
5
+ #ifndef RGEO_GEOS_ANALYSIS_INCLUDED
6
+ #define RGEO_GEOS_ANALYSIS_INCLUDED
7
+
8
+ #include <ruby.h>
9
+
10
+ #ifdef RGEO_GEOS_SUPPORTED
11
+
12
+ #include "factory.h"
13
+
14
+ RGEO_BEGIN_C
15
+
16
+ /*
17
+ * call-seq:
18
+ * RGeo::Geos::Analysis.ccw? -> true or false
19
+ *
20
+ * Checks direction for a ring, returns +true+ if counter-clockwise, +false+
21
+ * otherwise.
22
+ */
23
+ #ifdef RGEO_GEOS_SUPPORTS_CCW
24
+ VALUE rgeo_geos_analysis_ccw_p(VALUE self, VALUE ring);
25
+ #endif // RGEO_GEOS_SUPPORTS_CCW
26
+
27
+ /**
28
+ * call-seq:
29
+ * RGeo::Geos::Analysis.ccw_supported? -> true or false
30
+ *
31
+ * Checks if the RGEO_GEOS_SUPPORTS_ISCCW macro is defined, returns +true+
32
+ * if it is, +false+ otherwise
33
+ */
34
+ VALUE rgeo_geos_analysis_supports_ccw(VALUE self);
35
+
36
+ void rgeo_init_geos_analysis(RGeo_Globals* globals);
37
+
38
+ RGEO_END_C
39
+
40
+ #endif // RGEO_GEOS_SUPPORTED
41
+
42
+ #endif // RGEO_GEOS_ANALYSIS_INCLUDED
@@ -0,0 +1,35 @@
1
+
2
+ #ifndef RGEO_GEOS_ERROS_INCLUDED
3
+ #define RGEO_GEOS_ERROS_INCLUDED
4
+
5
+ #include <ruby.h>
6
+
7
+ #include "preface.h"
8
+
9
+ #ifdef RGEO_GEOS_SUPPORTED
10
+
11
+ #include "errors.h"
12
+
13
+ RGEO_BEGIN_C
14
+
15
+ // Any error relative to RGeo.
16
+ VALUE rgeo_error;
17
+ // RGeo error specific to the GEOS implementation.
18
+ VALUE geos_error;
19
+
20
+
21
+ void rgeo_init_geos_errors() {
22
+ VALUE rgeo_module;
23
+ VALUE error_module;
24
+
25
+ rgeo_module = rb_define_module("RGeo");
26
+ error_module = rb_define_module_under(rgeo_module, "Error");
27
+ rgeo_error = rb_define_class_under(error_module, "RGeoError", rb_eRuntimeError);
28
+ geos_error = rb_define_class_under(error_module, "GeosError", rgeo_error);
29
+ }
30
+
31
+ RGEO_END_C
32
+
33
+ #endif // RGEO_GEOS_SUPPORTED
34
+
35
+ #endif // RGEO_GEOS_ERROS_INCLUDED
@@ -0,0 +1,22 @@
1
+
2
+ #ifndef RGEO_GEOS_ERROS_INCLUDED
3
+ #define RGEO_GEOS_ERROS_INCLUDED
4
+
5
+ #include <ruby.h>
6
+
7
+ #ifdef RGEO_GEOS_SUPPORTED
8
+
9
+ RGEO_BEGIN_C
10
+
11
+ // Any error relative to RGeo.
12
+ extern VALUE rgeo_error;
13
+ // RGeo error specific to the GEOS implementation.
14
+ extern VALUE geos_error;
15
+
16
+ void rgeo_init_geos_errors();
17
+
18
+ RGEO_END_C
19
+
20
+ #endif // RGEO_GEOS_SUPPORTED
21
+
22
+ #endif // RGEO_GEOS_ERROS_INCLUDED
@@ -31,6 +31,7 @@ else
31
31
  have_func("GEOSPreparedContains_r", "geos_c.h")
32
32
  have_func("GEOSPreparedDisjoint_r", "geos_c.h")
33
33
  have_func("GEOSUnaryUnion_r", "geos_c.h")
34
+ have_func("GEOSCoordSeq_isCCW_r", "geos_c.h")
34
35
  have_func("rb_memhash", "ruby.h")
35
36
  end
36
37
 
@@ -16,6 +16,7 @@
16
16
  #include "line_string.h"
17
17
  #include "polygon.h"
18
18
  #include "geometry_collection.h"
19
+ #include "errors.h"
19
20
 
20
21
  RGEO_BEGIN_C
21
22
 
@@ -576,10 +577,11 @@ RGeo_Globals* rgeo_init_geos_factory()
576
577
  VALUE wrapped_globals;
577
578
  VALUE feature_module;
578
579
 
580
+ rgeo_module = rb_define_module("RGeo");
581
+
579
582
  globals = ALLOC(RGeo_Globals);
580
583
 
581
584
  // Cache some modules so we don't have to look them up by name every time
582
- rgeo_module = rb_define_module("RGeo");
583
585
  feature_module = rb_define_module_under(rgeo_module, "Feature");
584
586
  globals->feature_module = feature_module;
585
587
  globals->geos_module = rb_define_module_under(rgeo_module, "Geos");
@@ -831,6 +833,13 @@ char rgeo_is_geos_object(VALUE obj)
831
833
  return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? 1 : 0;
832
834
  }
833
835
 
836
+ void rgeo_check_geos_object(VALUE obj)
837
+ {
838
+ if (!rgeo_is_geos_object(obj)) {
839
+ rb_raise(rgeo_error, "Not a GEOS Geometry object.");
840
+ }
841
+ }
842
+
834
843
 
835
844
  const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj)
836
845
  {
@@ -10,7 +10,6 @@
10
10
 
11
11
  RGEO_BEGIN_C
12
12
 
13
-
14
13
  /*
15
14
  Per-interpreter globals.
16
15
  Most of these are cached references to commonly used classes, modules,
@@ -187,6 +186,11 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
187
186
  */
188
187
  char rgeo_is_geos_object(VALUE obj);
189
188
 
189
+ /*
190
+ Raises a rgeo error if the object is not a GEOS Geometry implementation.
191
+ */
192
+ void rgeo_check_geos_object(VALUE obj);
193
+
190
194
  /*
191
195
  Gets the underlying GEOS geometry for a given ruby object. Returns NULL
192
196
  if the given ruby object is not a GEOS geometry wrapper.
@@ -2,7 +2,6 @@
2
2
  Main initializer for GEOS wrapper
3
3
  */
4
4
 
5
-
6
5
  #include "preface.h"
7
6
 
8
7
  #ifdef RGEO_GEOS_SUPPORTED
@@ -10,18 +9,20 @@
10
9
  #include <ruby.h>
11
10
  #include <geos_c.h>
12
11
 
12
+ #include "errors.h"
13
+
13
14
  #include "factory.h"
14
15
  #include "geometry.h"
15
16
  #include "point.h"
16
17
  #include "line_string.h"
17
18
  #include "polygon.h"
18
19
  #include "geometry_collection.h"
20
+ #include "analysis.h"
19
21
 
20
22
  #endif
21
23
 
22
24
  RGEO_BEGIN_C
23
25
 
24
-
25
26
  void Init_geos_c_impl()
26
27
  {
27
28
  #ifdef RGEO_GEOS_SUPPORTED
@@ -33,6 +34,8 @@ void Init_geos_c_impl()
33
34
  rgeo_init_geos_line_string(globals);
34
35
  rgeo_init_geos_polygon(globals);
35
36
  rgeo_init_geos_geometry_collection(globals);
37
+ rgeo_init_geos_analysis(globals);
38
+ rgeo_init_geos_errors();
36
39
  #endif
37
40
  }
38
41
 
@@ -21,6 +21,9 @@
21
21
  #ifdef HAVE_GEOSUNARYUNION_R
22
22
  #define RGEO_GEOS_SUPPORTS_UNARYUNION
23
23
  #endif
24
+ #ifdef HAVE_GEOSCOORDSEQ_ISCCW_R
25
+ #define RGEO_GEOS_SUPPORTS_ISCCW
26
+ #endif
24
27
  #ifdef HAVE_RB_MEMHASH
25
28
  #define RGEO_SUPPORTS_NEW_HASHING
26
29
  #endif
@@ -75,12 +75,12 @@
75
75
  # database, and based on the postgresql adapter. Available as the
76
76
  # activerecord-postgis-adapter gem.
77
77
 
78
- require "rgeo/version"
79
- require "rgeo/error"
80
- require "rgeo/feature"
81
- require "rgeo/coord_sys"
82
- require "rgeo/impl_helper"
83
- require "rgeo/wkrep"
84
- require "rgeo/geos"
85
- require "rgeo/cartesian"
86
- require "rgeo/geographic"
78
+ require_relative "rgeo/version"
79
+ require_relative "rgeo/error"
80
+ require_relative "rgeo/feature"
81
+ require_relative "rgeo/coord_sys"
82
+ require_relative "rgeo/impl_helper"
83
+ require_relative "rgeo/wkrep"
84
+ require_relative "rgeo/geos"
85
+ require_relative "rgeo/cartesian"
86
+ require_relative "rgeo/geographic"
@@ -6,10 +6,10 @@
6
6
  # the simple Cartesian implementation. It also provides a namespace
7
7
  # for Cartesian-specific analysis tools.
8
8
 
9
- require "rgeo/cartesian/calculations"
10
- require "rgeo/cartesian/feature_methods"
11
- require "rgeo/cartesian/feature_classes"
12
- require "rgeo/cartesian/factory"
13
- require "rgeo/cartesian/interface"
14
- require "rgeo/cartesian/bounding_box"
15
- require "rgeo/cartesian/analysis"
9
+ require_relative "cartesian/calculations"
10
+ require_relative "cartesian/feature_methods"
11
+ require_relative "cartesian/feature_classes"
12
+ require_relative "cartesian/factory"
13
+ require_relative "cartesian/interface"
14
+ require_relative "cartesian/bounding_box"
15
+ require_relative "cartesian/analysis"
@@ -13,6 +13,28 @@ module RGeo
13
13
 
14
14
  module Analysis
15
15
  class << self
16
+ # Check orientation of a ring, returns `true` if it is counter-clockwise
17
+ # and false otherwise.
18
+ #
19
+ # If the factory used is GEOS based, use the GEOS implementation to
20
+ # check that. Otherwise, this methods falls back to `ring_direction`.
21
+ #
22
+ # == Note
23
+ #
24
+ # This method does not ensure a correct result for an invalid geometry.
25
+ # You should make sure your ring is valid beforehand using `is_ring?`
26
+ # if you are using a LineString, or directly `valid?` for a
27
+ # `linear_ring?`.
28
+ # This will be subject to changes in v3.
29
+ def ccw?(ring)
30
+ if RGeo::Geos.is_capi_geos?(ring) && RGeo::Geos::Analysis.ccw_supported?
31
+ RGeo::Geos::Analysis.ccw?(ring)
32
+ else
33
+ RGeo::Cartesian::Analysis.ring_direction(ring) == 1
34
+ end
35
+ end
36
+ alias counter_clockwise? ccw?
37
+
16
38
  # Given a LineString, which must be a ring, determine whether the
17
39
  # ring proceeds clockwise or counterclockwise.
18
40
  # Returns 1 for counterclockwise, or -1 for clockwise.
@@ -6,12 +6,12 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- require "rgeo/coord_sys/cs/factories"
10
- require "rgeo/coord_sys/cs/entities"
11
- require "rgeo/coord_sys/cs/wkt_parser"
12
- require "rgeo/coord_sys/srs_database/entry"
13
- require "rgeo/coord_sys/srs_database/url_reader"
14
- require "rgeo/coord_sys/srs_database/sr_org"
9
+ require_relative "coord_sys/cs/factories"
10
+ require_relative "coord_sys/cs/entities"
11
+ require_relative "coord_sys/cs/wkt_parser"
12
+ require_relative "coord_sys/srs_database/entry"
13
+ require_relative "coord_sys/srs_database/url_reader"
14
+ require_relative "coord_sys/srs_database/sr_org"
15
15
 
16
16
  module RGeo
17
17
  # This module provides data structures and tools related to coordinate
@@ -14,6 +14,10 @@ module RGeo
14
14
  class RGeoError < RuntimeError
15
15
  end
16
16
 
17
+ # RGeo error specific to the GEOS implementation.
18
+ class GeosError < RGeoError
19
+ end
20
+
17
21
  # The specified geometry is invalid
18
22
  class InvalidGeometry < RGeoError
19
23
  end
@@ -24,20 +24,20 @@
24
24
  # itself. The implementation should separately document any such
25
25
  # extensions that it may provide.
26
26
 
27
- require "rgeo/feature/factory"
28
- require "rgeo/feature/types"
29
- require "rgeo/feature/geometry"
30
- require "rgeo/feature/point"
31
- require "rgeo/feature/curve"
32
- require "rgeo/feature/line_string"
33
- require "rgeo/feature/linear_ring"
34
- require "rgeo/feature/line"
35
- require "rgeo/feature/surface"
36
- require "rgeo/feature/polygon"
37
- require "rgeo/feature/geometry_collection"
38
- require "rgeo/feature/multi_point"
39
- require "rgeo/feature/multi_curve"
40
- require "rgeo/feature/multi_line_string"
41
- require "rgeo/feature/multi_surface"
42
- require "rgeo/feature/multi_polygon"
43
- require "rgeo/feature/factory_generator"
27
+ require_relative "feature/factory"
28
+ require_relative "feature/types"
29
+ require_relative "feature/geometry"
30
+ require_relative "feature/point"
31
+ require_relative "feature/curve"
32
+ require_relative "feature/line_string"
33
+ require_relative "feature/linear_ring"
34
+ require_relative "feature/line"
35
+ require_relative "feature/surface"
36
+ require_relative "feature/polygon"
37
+ require_relative "feature/geometry_collection"
38
+ require_relative "feature/multi_point"
39
+ require_relative "feature/multi_curve"
40
+ require_relative "feature/multi_line_string"
41
+ require_relative "feature/multi_surface"
42
+ require_relative "feature/multi_polygon"
43
+ require_relative "feature/factory_generator"
@@ -23,6 +23,16 @@ module RGeo
23
23
  module LinearRing
24
24
  include LineString
25
25
  extend Type
26
+
27
+ # Returns +true+ if the ring is oriented in a counter clockwise direction
28
+ # otherwise returns +false+.
29
+ #
30
+ # == Notes
31
+ #
32
+ # Not a standard SFS method for linear rings, but added for convenience.
33
+ def ccw?
34
+ raise Error::UnsupportedOperation, "Method LinearRing#ccw? not defined."
35
+ end
26
36
  end
27
37
  end
28
38
  end
@@ -18,13 +18,13 @@
18
18
  # See the various class methods of Geographic for more information on
19
19
  # the behaviors of the factories they generate.
20
20
 
21
- require "rgeo/geographic/factory"
22
- require "rgeo/geographic/projected_window"
23
- require "rgeo/geographic/interface"
24
- require "rgeo/geographic/spherical_math"
25
- require "rgeo/geographic/spherical_feature_methods"
26
- require "rgeo/geographic/spherical_feature_classes"
27
- require "rgeo/geographic/proj4_projector"
28
- require "rgeo/geographic/simple_mercator_projector"
29
- require "rgeo/geographic/projected_feature_methods"
30
- require "rgeo/geographic/projected_feature_classes"
21
+ require_relative "geographic/factory"
22
+ require_relative "geographic/projected_window"
23
+ require_relative "geographic/interface"
24
+ require_relative "geographic/spherical_math"
25
+ require_relative "geographic/spherical_feature_methods"
26
+ require_relative "geographic/spherical_feature_classes"
27
+ require_relative "geographic/proj4_projector"
28
+ require_relative "geographic/simple_mercator_projector"
29
+ require_relative "geographic/projected_feature_methods"
30
+ require_relative "geographic/projected_feature_classes"
@@ -47,6 +47,7 @@ module RGeo
47
47
  include ImplHelper::BasicGeometryMethods
48
48
  include ImplHelper::BasicPolygonMethods
49
49
  include SphericalGeometryMethods
50
+ include SphericalPolygonMethods
50
51
  end
51
52
 
52
53
  class SphericalGeometryCollectionImpl # :nodoc:
@@ -130,5 +130,28 @@ module RGeo
130
130
  inject(0.0) { |sum, geom| sum + geom.length }
131
131
  end
132
132
  end
133
+
134
+ module SphericalPolygonMethods # :nodoc:
135
+ def centroid
136
+ return super unless num_interior_rings == 0
137
+
138
+ centroid_lat = 0.0
139
+ centroid_lng = 0.0
140
+ signed_area = 0.0
141
+
142
+ exterior_ring.points.each_cons(2) do |p0, p1|
143
+ area = (p0.x * p1.y) - (p1.x * p0.y)
144
+ signed_area += area
145
+ centroid_lat += (p0.x + p1.x) * area
146
+ centroid_lng += (p0.y + p1.y) * area
147
+ end
148
+
149
+ signed_area *= 0.5
150
+ centroid_lat /= (6.0 * signed_area)
151
+ centroid_lng /= (6.0 * signed_area)
152
+
153
+ RGeo::Geographic.spherical_factory.point(centroid_lat, centroid_lng)
154
+ end
155
+ end
133
156
  end
134
157
  end
@@ -21,24 +21,24 @@
21
21
 
22
22
  module RGeo
23
23
  module Geos
24
- require "rgeo/geos/utils"
25
- require "rgeo/geos/interface"
24
+ require_relative "geos/utils"
25
+ require_relative "geos/interface"
26
26
  begin
27
- require "rgeo/geos/geos_c_impl"
27
+ require_relative "geos/geos_c_impl"
28
28
  rescue LoadError
29
29
  # continue
30
30
  end
31
31
  CAPI_SUPPORTED = RGeo::Geos.const_defined?(:CAPIGeometryMethods)
32
32
  if CAPI_SUPPORTED
33
- require "rgeo/geos/capi_feature_classes"
34
- require "rgeo/geos/capi_factory"
33
+ require_relative "geos/capi_feature_classes"
34
+ require_relative "geos/capi_factory"
35
35
  end
36
- require "rgeo/geos/ffi_feature_methods"
37
- require "rgeo/geos/ffi_feature_classes"
38
- require "rgeo/geos/ffi_factory"
39
- require "rgeo/geos/zm_feature_methods"
40
- require "rgeo/geos/zm_feature_classes"
41
- require "rgeo/geos/zm_factory"
36
+ require_relative "geos/ffi_feature_methods"
37
+ require_relative "geos/ffi_feature_classes"
38
+ require_relative "geos/ffi_factory"
39
+ require_relative "geos/zm_feature_methods"
40
+ require_relative "geos/zm_feature_classes"
41
+ require_relative "geos/zm_factory"
42
42
 
43
43
  # Determine ffi support.
44
44
  begin
@@ -297,10 +297,10 @@ module RGeo
297
297
  if (wkb_parser_ = _wkb_parser)
298
298
  wkb_parser_.parse(str_)
299
299
  else
300
- if str_[0] =~ /[0-oa-fA-F]/
301
- _parse_wkb_impl([str_].pack('H*'))
302
- else
300
+ if str_[0] == "\x00" || str_[0] == "\x01"
303
301
  _parse_wkb_impl(str_)
302
+ else
303
+ _parse_wkb_impl([str_].pack('H*'))
304
304
  end
305
305
  end
306
306
  end
@@ -72,6 +72,10 @@ module RGeo
72
72
  include CAPIGeometryMethods
73
73
  include CAPILineStringMethods
74
74
  include CAPILinearRingMethods
75
+
76
+ def ccw?
77
+ RGeo::Cartesian::Analysis.ccw?(self)
78
+ end
75
79
  end
76
80
 
77
81
  class CAPILineImpl # :nodoc:
@@ -393,6 +393,10 @@ module RGeo
393
393
  def geometry_type
394
394
  Feature::LinearRing
395
395
  end
396
+
397
+ def ccw?
398
+ RGeo::Cartesian::Analysis.ccw?(self)
399
+ end
396
400
  end
397
401
 
398
402
  module FFILineMethods # :nodoc:
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rgeo/impl_helper/utils"
4
- require "rgeo/impl_helper/math"
5
- require "rgeo/impl_helper/basic_geometry_methods"
6
- require "rgeo/impl_helper/basic_geometry_collection_methods"
7
- require "rgeo/impl_helper/basic_point_methods"
8
- require "rgeo/impl_helper/basic_line_string_methods"
9
- require "rgeo/impl_helper/basic_polygon_methods"
3
+ require_relative "impl_helper/utils"
4
+ require_relative "impl_helper/math"
5
+ require_relative "impl_helper/basic_geometry_methods"
6
+ require_relative "impl_helper/basic_geometry_collection_methods"
7
+ require_relative "impl_helper/basic_point_methods"
8
+ require_relative "impl_helper/basic_line_string_methods"
9
+ require_relative "impl_helper/basic_polygon_methods"
@@ -114,6 +114,12 @@ module RGeo
114
114
  @elements.map(&:coordinates)
115
115
  end
116
116
 
117
+ def contains?(rhs)
118
+ return super unless Feature::Point === rhs
119
+
120
+ @elements.any? { |line| line.contains?(rhs) }
121
+ end
122
+
117
123
  private
118
124
 
119
125
  def add_boundary(hash, point)
@@ -171,12 +177,18 @@ module RGeo
171
177
  array << poly.exterior_ring unless poly.is_empty?
172
178
  array.concat(poly.interior_rings)
173
179
  end
174
- factory.multilinestring(array)
180
+ factory.multi_line_string(array)
175
181
  end
176
182
 
177
183
  def coordinates
178
184
  @elements.map(&:coordinates)
179
185
  end
186
+
187
+ def contains?(rhs)
188
+ return super unless Feature::Point === rhs
189
+
190
+ @elements.any? { |poly| poly.contains?(rhs) }
191
+ end
180
192
  end
181
193
  end
182
194
  end
@@ -87,8 +87,43 @@ module RGeo
87
87
  @points.map(&:coordinates)
88
88
  end
89
89
 
90
+ def contains?(rhs)
91
+ if Feature::Point === rhs
92
+ contains_point?(rhs)
93
+ else
94
+ raise(Error::UnsupportedOperation,
95
+ "Method LineString#contains? is only defined for Point")
96
+ end
97
+ end
98
+
90
99
  private
91
100
 
101
+ def contains_point?(point)
102
+ @points.each_cons(2) do |start_point, end_point|
103
+ return true if point_intersect_segment?(point, start_point, end_point)
104
+ end
105
+ false
106
+ end
107
+
108
+ def point_intersect_segment?(point, start_point, end_point)
109
+ return false unless point_collinear?(point, start_point, end_point)
110
+
111
+ if start_point.x != end_point.x
112
+ between_coordinate?(point.x, start_point.x, end_point.x)
113
+ else
114
+ between_coordinate?(point.y, start_point.y, end_point.y)
115
+ end
116
+ end
117
+
118
+ def point_collinear?(a, b, c)
119
+ (b.x - a.x) * (c.y - a.y) == (c.x - a.x) * (b.y - a.y)
120
+ end
121
+
122
+ def between_coordinate?(coord, start_coord, end_coord)
123
+ end_coord >= coord && coord >= start_coord ||
124
+ start_coord >= coord && coord >= end_coord
125
+ end
126
+
92
127
  def copy_state_from(obj)
93
128
  super
94
129
  @points = obj.points
@@ -137,6 +172,10 @@ module RGeo
137
172
  Feature::LinearRing
138
173
  end
139
174
 
175
+ def ccw?
176
+ RGeo::Cartesian::Analysis.ccw?(self)
177
+ end
178
+
140
179
  private
141
180
 
142
181
  def validate_geometry
@@ -79,8 +79,45 @@ module RGeo
79
79
  ([@exterior_ring] + @interior_rings).map(&:coordinates)
80
80
  end
81
81
 
82
+ def contains?(rhs)
83
+ if Feature::Point === rhs
84
+ contains_point?(rhs)
85
+ else
86
+ raise(Error::UnsupportedOperation,
87
+ "Method Polygon#contains? is only defined for Point"
88
+ )
89
+ end
90
+ end
91
+
82
92
  private
83
93
 
94
+ def contains_point?(point)
95
+ ring_encloses_point?(@exterior_ring, point) &&
96
+ !@interior_rings.any? do |exclusion|
97
+ ring_encloses_point?(exclusion, point, on_border_return: true)
98
+ end
99
+ end
100
+
101
+ def ring_encloses_point?(ring, point, on_border_return: false)
102
+ # This is an implementation of the ray casting algorithm, greatly inspired
103
+ # by https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html
104
+ # Since this algorithm does not handle point on edge, we check first if
105
+ # the ring is on the border.
106
+ # on_border_return is used for exclusion ring
107
+ return on_border_return if ring.contains?(point)
108
+ encloses_point = false
109
+ ring.points.each_cons(2) do |start_point, end_point|
110
+ next unless (point.y < end_point.y) != (point.y < start_point.y)
111
+
112
+ if point.x < (end_point.x - start_point.x) * (point.y - start_point.y) /
113
+ (end_point.y - start_point.y) + start_point.x
114
+ encloses_point = !encloses_point
115
+ end
116
+ end
117
+ encloses_point
118
+ end
119
+
120
+
84
121
  def copy_state_from(obj)
85
122
  super
86
123
  @exterior_ring = obj.exterior_ring
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RGeo
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.0"
5
5
  end
@@ -21,7 +21,7 @@
21
21
  # To parse a byte string in WKB (well-known binary) format back into a
22
22
  # geometry object, use the WKRep::WKBParser class.
23
23
 
24
- require "rgeo/wkrep/wkt_parser"
25
- require "rgeo/wkrep/wkt_generator"
26
- require "rgeo/wkrep/wkb_parser"
27
- require "rgeo/wkrep/wkb_generator"
24
+ require_relative "wkrep/wkt_parser"
25
+ require_relative "wkrep/wkt_generator"
26
+ require_relative "wkrep/wkb_parser"
27
+ require_relative "wkrep/wkb_generator"
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgeo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
- - Daniel Azuma, Tee Parham
7
+ - Daniel Azuma
8
+ - Tee Parham
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2019-08-26 00:00:00.000000000 Z
12
+ date: 2020-11-19 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: ffi-geos
@@ -85,15 +86,23 @@ description: RGeo is a geospatial data library for Ruby. It provides an implemen
85
86
  standard spatial/geographic data storage systems such as PostGIS. A number of add-on
86
87
  modules are also available to help with writing location-based applications using
87
88
  Ruby-based frameworks such as Ruby On Rails.
88
- email: dazuma@gmail.com, parhameter@gmail.com
89
+ email:
90
+ - dazuma@gmail.com
91
+ - parhameter@gmail.com
92
+ - kfdoggett@gmail.com
89
93
  executables: []
90
94
  extensions:
91
95
  - ext/geos_c_impl/extconf.rb
92
96
  extra_rdoc_files: []
93
97
  files:
94
98
  - LICENSE.txt
99
+ - README.md
100
+ - ext/geos_c_impl/analysis.c
101
+ - ext/geos_c_impl/analysis.h
95
102
  - ext/geos_c_impl/coordinates.c
96
103
  - ext/geos_c_impl/coordinates.h
104
+ - ext/geos_c_impl/errors.c
105
+ - ext/geos_c_impl/errors.h
97
106
  - ext/geos_c_impl/extconf.rb
98
107
  - ext/geos_c_impl/factory.c
99
108
  - ext/geos_c_impl/factory.h
@@ -181,7 +190,8 @@ files:
181
190
  - lib/rgeo/wkrep/wkt_generator.rb
182
191
  - lib/rgeo/wkrep/wkt_parser.rb
183
192
  homepage: https://github.com/rgeo/rgeo
184
- licenses: []
193
+ licenses:
194
+ - BSD-3-Clause
185
195
  metadata: {}
186
196
  post_install_message:
187
197
  rdoc_options: []
@@ -191,14 +201,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
201
  requirements:
192
202
  - - ">="
193
203
  - !ruby/object:Gem::Version
194
- version: 2.3.0
204
+ version: 2.4.0
195
205
  required_rubygems_version: !ruby/object:Gem::Requirement
196
206
  requirements:
197
207
  - - ">="
198
208
  - !ruby/object:Gem::Version
199
209
  version: '0'
200
210
  requirements: []
201
- rubygems_version: 3.0.6
211
+ rubygems_version: 3.0.3
202
212
  signing_key:
203
213
  specification_version: 4
204
214
  summary: RGeo is a geospatial data library for Ruby.