charta 0.2.3 → 0.3.0

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/charta.gemspec +20 -20
  3. data/lib/charta.rb +36 -89
  4. data/lib/charta/coordinates.rb +17 -17
  5. data/lib/charta/ewkt_serializer.rb +10 -1
  6. data/lib/charta/factory/ewkt_feature_builder.rb +17 -0
  7. data/lib/charta/factory/feature_factory_base.rb +15 -0
  8. data/lib/charta/factory/simple_feature_factory.rb +50 -0
  9. data/lib/charta/factory/simple_geometry_factory.rb +46 -0
  10. data/lib/charta/factory/srid_provider.rb +36 -0
  11. data/lib/charta/factory/transformers/ewkt_passthrough.rb +20 -0
  12. data/lib/charta/factory/transformers/ewkt_transformer.rb +20 -0
  13. data/lib/charta/factory/transformers/ewkt_transformer_chain.rb +42 -0
  14. data/lib/charta/factory/transformers/from_geo_json_transformer.rb +20 -0
  15. data/lib/charta/factory/transformers/from_gml_transformer.rb +20 -0
  16. data/lib/charta/factory/transformers/from_kml_transformer.rb +20 -0
  17. data/lib/charta/factory/transformers/from_wkb_transformer.rb +24 -0
  18. data/lib/charta/factory/transformers/transformation_error.rb +10 -0
  19. data/lib/charta/geo_json.rb +4 -1
  20. data/lib/charta/geometry.rb +22 -12
  21. data/lib/charta/geometry_collection.rb +6 -4
  22. data/lib/charta/gml.rb +18 -2
  23. data/lib/charta/gml_import.rb +24 -24
  24. data/lib/charta/kml.rb +21 -3
  25. data/lib/charta/multi_polygon.rb +1 -1
  26. data/lib/charta/point.rb +2 -1
  27. data/lib/charta/version.rb +1 -1
  28. data/lib/rgeo/svg.rb +44 -44
  29. metadata +65 -46
  30. data/.gitignore +0 -13
  31. data/.gitlab-ci.yml +0 -14
  32. data/.travis.yml +0 -7
  33. data/CODE_OF_CONDUCT.md +0 -74
  34. data/Gemfile +0 -4
  35. data/LICENSE.txt +0 -21
  36. data/README.md +0 -44
  37. data/Rakefile +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fbd9a97d2afc3f7fac4856628353c24a686fad2a416c0d12dbb00b448f6d9a4
4
- data.tar.gz: '0267836321e3643033bcd873e7672144a37bf0f0b293cd9440a7f01de84a02dc'
3
+ metadata.gz: 8f153424d966d80706e24233539f19c1efa2f7f5d013ac299046e51bd98e3ad8
4
+ data.tar.gz: '09fcff41f2a1f3d4a3cda3786c4a882f16b79cd551bda14c4083ebc351561956'
5
5
  SHA512:
6
- metadata.gz: 76960df71f7e14223da5c28b93dfad64f6ffd563609408cf04eea019afb23c1f7fbeaf3a49775a251152581ac6650a8d9688e7d96230d3aed687cdcb90390eda
7
- data.tar.gz: a987c577129ff328b5b8ae574b28dc83ea0a54a308c6e02c0986db53837f06d62429545c48dac75bd5a96b241f98beaaf6d63a5eab3d51ad56abfc31ffac3de3
6
+ metadata.gz: 2a366f56215565b6183f990e5cdd10a829871f0280bf923aaad2e7ab3afca35432196b24d5b921a41de5a763efda7b2672be2b8c3f93003f78583829ab8222a5
7
+ data.tar.gz: b19fece238165742bf01a44d2f7b500801629f2325737b1a36c9997d4a5e42ed12555299454ca4ae03db477a4ef69e84fec85dd3e66970865bfe60a8771c09a9
data/charta.gemspec CHANGED
@@ -1,30 +1,30 @@
1
- lib = File.expand_path('../lib', __FILE__)
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'charta/version'
1
+ require_relative 'lib/charta/version'
4
2
 
5
3
  Gem::Specification.new do |spec|
6
- spec.name = 'charta'
7
- spec.version = Charta::VERSION
8
- spec.authors = ['Brice TEXIER']
9
- spec.email = ['brice@ekylibre.com']
4
+ spec.name = 'charta'
5
+ spec.version = Charta::VERSION
6
+ spec.authors = ['Ekylibre developers']
7
+ spec.email = ['dev@ekylibre.com']
10
8
 
11
- spec.summary = 'Simple tool over geos and co'
12
- spec.homepage = 'https://github.com/ekylibre/charta'
13
- spec.license = 'MIT'
9
+ spec.summary = 'Simple tool over geos and co'
10
+ spec.required_ruby_version = '>= 2.6.0'
11
+ spec.homepage = 'https://gitlab.com/ekylibre'
12
+ spec.license = 'AGPL-3.0-only'
13
+
14
+ spec.files = Dir.glob(%w[lib/**/*.rb *.gemspec])
14
15
 
15
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
- f.match(%r{^(test|spec|features)/})
17
- end
18
16
  spec.require_paths = ['lib']
19
17
 
20
- spec.add_dependency 'nokogiri', '>= 1.7.0'
21
- spec.add_dependency 'rgeo', '~> 1.0'
22
- spec.add_dependency 'json', '>= 1.8.0'
23
- spec.add_dependency 'rgeo-geojson', '~> 1.0'
24
- spec.add_dependency 'rgeo-proj4', '~> 1.0'
25
18
  spec.add_dependency 'activesupport', '~> 5.0'
19
+ spec.add_dependency 'json', '>= 1.8.0'
20
+ spec.add_dependency 'nokogiri', '>= 1.7.0'
21
+ spec.add_dependency 'rgeo', '~> 2.0'
22
+ spec.add_dependency 'rgeo-geojson', '~> 2.0'
23
+ spec.add_dependency 'rgeo-proj4', '~> 2.0'
24
+ spec.add_dependency 'zeitwerk', '~> 2.4.0'
25
+
26
26
  spec.add_development_dependency 'bundler', '~> 2.0'
27
- spec.add_development_dependency 'rake', '~> 10.0'
28
27
  spec.add_development_dependency 'minitest', '~> 5.0'
29
- spec.add_development_dependency 'byebug'
28
+ spec.add_development_dependency 'rake', '~> 12.0'
29
+ spec.add_development_dependency 'rubocop', '1.3.1'
30
30
  end
data/lib/charta.rb CHANGED
@@ -4,19 +4,15 @@ require 'bigdecimal'
4
4
  require 'bigdecimal/util'
5
5
  require 'rgeo'
6
6
  require 'rgeo/proj4'
7
+ require 'zeitwerk'
7
8
 
8
- require 'charta/coordinates'
9
- require 'charta/ewkt_serializer'
10
- require 'charta/geometry'
11
- require 'charta/geometry_collection'
12
- require 'charta/point'
13
- require 'charta/line_string'
14
- require 'charta/polygon'
15
- require 'charta/multi_polygon'
16
- require 'charta/bounding_box'
17
- require 'charta/geo_json'
18
- require 'charta/gml'
19
- require 'charta/kml'
9
+ loader = Zeitwerk::Loader.for_gem
10
+ loader.inflector.inflect(
11
+ 'geo_json' => 'GeoJSON',
12
+ 'gml' => 'GML',
13
+ 'kml' => 'KML'
14
+ )
15
+ loader.setup
20
16
 
21
17
  unless RGeo::CoordSys::Proj4.supported?
22
18
  puts "Proj4 is not supported. Some actions won't work"
@@ -31,75 +27,27 @@ module Charta
31
27
  }.freeze
32
28
 
33
29
  class << self
30
+ def default_feature_factory=(factory)
31
+ @default_feature_factory = factory
32
+ @geometry_factory = nil
33
+ end
34
+
35
+ # @deprecated This is deprecated and will be removed in 0.4
36
+ def default_feature_factory
37
+ @default_feature_factory || (self.default_feature_factory = Factory::SimpleFeatureFactory.build)
38
+ end
39
+
40
+ def geometry_factory
41
+ @geometry_factory ||= Factory::SimpleGeometryFactory.new(feature_factory: default_feature_factory)
42
+ end
43
+
44
+ # @deprecated This is deprecated and will be removed in 0.4
34
45
  def new_feature(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
35
- geom_ewkt = nil
36
- if coordinates.is_a?(RGeo::Feature::Instance)
37
- return Geometry.feature(coordinates)
38
- elsif coordinates.is_a?(::Charta::Geometry)
39
- return coordinates
40
- elsif coordinates.to_s =~ /\A[[:space:]]*\z/
41
- geom_ewkt = empty_geometry(srs).to_ewkt
42
- elsif coordinates.is_a?(Hash) || (coordinates.is_a?(String) && ::Charta::GeoJSON.valid?(coordinates)) # GeoJSON
43
- srid = srs ? find_srid(srs) : :WGS84
44
- geom_ewkt = ::Charta::GeoJSON.new(coordinates, srid).to_ewkt
45
- elsif coordinates.is_a?(String)
46
- geom_ewkt = if coordinates =~ /\A[A-F0-9]+\z/ # WKB
47
- if srs && srid = find_srid(srs)
48
- generate_ewkt RGeo::Geos.factory(srid: srid).parse_wkb(coordinates)
49
- else
50
- generate_ewkt Geometry.factory.parse_wkb(coordinates)
51
- end
52
- elsif format == 'gml' && ::Charta::GML.valid?(coordinates)
53
- # required format 'cause kml geometries return empty instead of failing
54
- ::Charta::GML.new(coordinates, srid).to_ewkt
55
- elsif format == 'kml' && ::Charta::KML.valid?(coordinates)
56
- ::Charta::KML.new(coordinates).to_ewkt
57
- elsif coordinates =~ /^SRID\=\d+\;/i
58
- if feature = Geometry.feature(coordinates)
59
- generate_ewkt feature
60
- else
61
- Charta::GeometryCollection.empty.feature
62
- end
63
- else # WKT expected
64
- if srs && srid = find_srid(srs)
65
- begin
66
- f = RGeo::Geos.factory(srid: srid).parse_wkt(coordinates)
67
- rescue RGeo::Error::ParseError => e
68
- raise "Invalid EWKT (#{e.message}): #{coordinates}"
69
- end
70
- generate_ewkt f
71
- else
72
- generate_ewkt Geometry.feature(coordinates)
73
- end
74
- end
75
- else # Default for RGeo
76
- geom_ewkt = generate_ewkt coordinates
77
- end
78
- if geom_ewkt.to_s =~ /\A[[:space:]]*\z/
79
- raise ArgumentError, "Invalid data: coordinates=#{coordinates.inspect}, srid=#{srid.inspect}"
80
- end
81
- Geometry.feature(geom_ewkt)
46
+ default_feature_factory.new_feature(coordinates, srs: srs, format: format)
82
47
  end
83
48
 
84
49
  def new_geometry(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
85
- return coordinates if coordinates.is_a?(::Charta::Geometry)
86
- feature = Charta.new_feature(coordinates, srs, format, _flatten_collection, _options)
87
- type = feature.geometry_type
88
- geom = case type
89
- when RGeo::Feature::Point then
90
- Point.new(feature)
91
- when RGeo::Feature::LineString then
92
- LineString.new(feature)
93
- when RGeo::Feature::Polygon then
94
- Polygon.new(feature)
95
- when RGeo::Feature::MultiPolygon then
96
- MultiPolygon.new(feature)
97
- when RGeo::Feature::GeometryCollection then
98
- GeometryCollection.new(feature)
99
- else
100
- Geometry.new(feature)
101
- end
102
- geom
50
+ geometry_factory.new_geometry(coordinates, srs: srs, format: format)
103
51
  end
104
52
 
105
53
  def new_point(lat, lon, srid = 4326)
@@ -111,12 +59,18 @@ module Charta
111
59
  options[:srid] ||= new_geometry(points.first).srid if points.any?
112
60
  options[:srid] ||= 4326
113
61
 
114
- ewkt = "SRID=#{options[:srid]};LINESTRING(" + points.map { |wkt| p = new_geometry(wkt); "#{p.x} #{p.y}" }.join(', ') + ')'
62
+ points_coordinates = points.map do |wkt|
63
+ p = new_geometry(wkt)
64
+
65
+ "#{p.x} #{p.y}"
66
+ end
67
+
68
+ ewkt = "SRID=#{options[:srid]};LINESTRING(#{points_coordinates.join(', ')})"
115
69
  new_geometry(ewkt)
116
70
  end
117
71
 
118
72
  def empty_geometry(srid = :WGS84)
119
- GeometryCollection.empty(srid)
73
+ geometry_factory.empty_geometry(srid)
120
74
  end
121
75
 
122
76
  def generate_ewkt(feature)
@@ -143,23 +97,16 @@ module Charta
143
97
  end
144
98
 
145
99
  # Check and returns the SRID matching with srname or SRID.
100
+ # @deprecated
146
101
  def find_srid(srname_or_srid)
147
- if srname_or_srid.to_s =~ /\Aurn:ogc:def:crs:.*\z/
148
- x = srname_or_srid.split(':').last.upcase.to_sym
149
- SRS[x] || x
150
- elsif srname_or_srid.to_s =~ /\AEPSG::?(\d{4,5})\z/
151
- srname_or_srid.split(':').last
152
- elsif srname_or_srid.to_s =~ /\A\d+\z/
153
- srname_or_srid.to_i
154
- else
155
- SRS[srname_or_srid] || srname_or_srid
156
- end
102
+ Factory::SridProvider.build.find(srname_or_srid)
157
103
  end
158
104
 
159
105
  def from(format, data)
160
106
  unless respond_to?("from_#{format}")
161
107
  raise "Unknown format: #{format.inspect}"
162
108
  end
109
+
163
110
  send("from_#{format}", data)
164
111
  end
165
112
 
@@ -9,12 +9,12 @@ module Charta
9
9
 
10
10
  def map_coordinates(hash, &block)
11
11
  case hash['type']
12
- when 'FeatureCollection'
13
- map_feature_collection_coordinates hash, &block
14
- when 'Feature'
15
- map_feature_coordinates hash, &block
16
- else
17
- map_geometry_coordinates hash, &block
12
+ when 'FeatureCollection'
13
+ map_feature_collection_coordinates hash, &block
14
+ when 'Feature'
15
+ map_feature_coordinates hash, &block
16
+ else
17
+ map_geometry_coordinates hash, &block
18
18
  end
19
19
  end
20
20
 
@@ -41,16 +41,16 @@ module Charta
41
41
  coordinates = hash['coordinates']
42
42
  mapped =
43
43
  case hash['type']
44
- when 'Point' then
45
- block.call coordinates
46
- when 'MultiPoint', 'LineString'
47
- coordinates.map(&block)
48
- when 'MultiLineString', 'Polygon'
49
- coordinates.map { |line| line.map(&block) }
50
- when 'MultiPolygon'
51
- coordinates.map { |poly| poly.map { |line| line.map(&block) } }
52
- else
53
- raise StandardError, "Cannot handle: #{hash['type'].inspect}. In #{hash.inspect}"
44
+ when 'Point'
45
+ block.call coordinates
46
+ when 'MultiPoint', 'LineString'
47
+ coordinates.map(&block)
48
+ when 'MultiLineString', 'Polygon'
49
+ coordinates.map { |line| line.map(&block) }
50
+ when 'MultiPolygon'
51
+ coordinates.map { |poly| poly.map { |line| line.map(&block) } }
52
+ else
53
+ raise StandardError.new("Cannot handle: #{hash['type'].inspect}. In #{hash.inspect}")
54
54
  end
55
55
 
56
56
  hash.merge 'coordinates' => mapped
@@ -62,4 +62,4 @@ module Charta
62
62
  end
63
63
  end
64
64
  end
65
- end
65
+ end
@@ -11,6 +11,7 @@ module Charta
11
11
 
12
12
  def feature_collection_to_ewkt(hash)
13
13
  return 'GEOMETRYCOLLECTION EMPTY' if hash['features'].nil?
14
+
14
15
  'GEOMETRYCOLLECTION(' + hash['features'].collect do |feature|
15
16
  object_to_ewkt(feature)
16
17
  end.join(', ') + ')'
@@ -18,6 +19,7 @@ module Charta
18
19
 
19
20
  def geometry_collection_to_ewkt(hash)
20
21
  return 'GEOMETRYCOLLECTION EMPTY' if hash['geometries'].nil?
22
+
21
23
  'GEOMETRYCOLLECTION(' + hash['geometries'].collect do |feature|
22
24
  object_to_ewkt(feature)
23
25
  end.join(', ') + ')'
@@ -29,11 +31,13 @@ module Charta
29
31
 
30
32
  def point_to_ewkt(hash)
31
33
  return 'POINT EMPTY' if hash['coordinates'].nil?
34
+
32
35
  'POINT(' + hash['coordinates'].join(' ') + ')'
33
36
  end
34
37
 
35
38
  def line_string_to_ewkt(hash)
36
39
  return 'LINESTRING EMPTY' if hash['coordinates'].nil?
40
+
37
41
  'LINESTRING(' + hash['coordinates'].collect do |point|
38
42
  point.join(' ')
39
43
  end.join(', ') + ')'
@@ -41,6 +45,7 @@ module Charta
41
45
 
42
46
  def polygon_to_ewkt(hash)
43
47
  return 'POLYGON EMPTY' if hash['coordinates'].nil?
48
+
44
49
  'POLYGON(' + hash['coordinates'].collect do |hole|
45
50
  '(' + hole.collect do |point|
46
51
  point.join(' ')
@@ -50,6 +55,7 @@ module Charta
50
55
 
51
56
  def multi_point_to_ewkt(hash)
52
57
  return 'MULTIPOINT EMPTY' if hash['coordinates'].nil?
58
+
53
59
  'MULTIPOINT(' + hash['coordinates'].collect do |point|
54
60
  '(' + point.join(' ') + ')'
55
61
  end.join(', ') + ')'
@@ -57,6 +63,7 @@ module Charta
57
63
 
58
64
  def multi_line_string_to_ewkt(hash)
59
65
  return 'MULTILINESTRING EMPTY' if hash['coordinates'].nil?
66
+
60
67
  'MULTILINESTRING(' + hash['coordinates'].collect do |line|
61
68
  '(' + line.collect do |point|
62
69
  point.join(' ')
@@ -66,6 +73,7 @@ module Charta
66
73
 
67
74
  def multipolygon_to_ewkt(hash)
68
75
  return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
76
+
69
77
  'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
70
78
  '(' + polygon.collect do |hole|
71
79
  '(' + hole.collect do |point|
@@ -78,6 +86,7 @@ module Charta
78
86
  # for PostGIS ST_ASGeoJSON compatibility
79
87
  def multi_polygon_to_ewkt(hash)
80
88
  return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
89
+
81
90
  'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
82
91
  '(' + polygon.collect do |hole|
83
92
  '(' + hole.collect do |point|
@@ -89,4 +98,4 @@ module Charta
89
98
  end
90
99
 
91
100
  end
92
- end
101
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class EwktFeatureBuilder
6
+ # @param [String] ewkt EWKT representation of a feature
7
+ # @return [RGeo::Feature::Instance]
8
+ def from_ewkt(ewkt)
9
+ if ewkt.to_s =~ /\A[[:space:]]*\z/
10
+ raise ArgumentError.new("Invalid data: #{ewkt.inspect}")
11
+ end
12
+
13
+ Geometry.feature(ewkt)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class FeatureFactoryBase
6
+ def new_feature(coordinates, srs: nil, format: nil)
7
+ raise StandardError.new('Not implemented')
8
+ end
9
+
10
+ def empty_feature(srs = :WGS84)
11
+ new_feature('GEOMETRYCOLLECTION EMPTY', srs: srs)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SimpleFeatureFactory < FeatureFactoryBase
6
+ class << self
7
+ def build
8
+ new(
9
+ ewkt_builder: EwktFeatureBuilder.new,
10
+ srid_provider: SridProvider.build,
11
+ transformer: Transformers::EwktTransformerChain.build
12
+ )
13
+ end
14
+ end
15
+
16
+ # @return [EwktFeatureBuilder]
17
+ attr_reader :ewkt_builder
18
+ # @return [SridProvider]
19
+ attr_reader :srid_provider
20
+ # @return [Transformers::EwktTransformer]
21
+ attr_reader :transformer
22
+
23
+ def initialize(ewkt_builder:, srid_provider:, transformer:)
24
+ @ewkt_builder = ewkt_builder
25
+ @srid_provider = srid_provider
26
+ @transformer = transformer
27
+ end
28
+
29
+ def new_feature(coordinates, srs: nil, format: nil)
30
+ if coordinates.is_a?(Charta::Geometry)
31
+ coordinates
32
+ elsif coordinates.is_a?(RGeo::Feature::Instance)
33
+ Geometry.feature(coordinates)
34
+ elsif coordinates.to_s =~ /\A[[:space:]]*\z/
35
+ empty_feature(srs)
36
+ else
37
+ convert_feature(coordinates, srs: srs, format: format)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def convert_feature(coordinates, srs: nil, format: nil)
44
+ srid = srs.nil? ? nil : srid_provider.find(srs)
45
+
46
+ ewkt_builder.from_ewkt(transformer.transform(coordinates, srid: srid, format: format))
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SimpleGeometryFactory
6
+ # @return [SimpleFeatureFactory]
7
+ attr_reader :feature_factory
8
+
9
+ # @param [SimpleFeatureFactory] feature_factory
10
+ def initialize(feature_factory:)
11
+ @feature_factory = feature_factory
12
+ end
13
+
14
+ def new_geometry(coordinates, srs: nil, format: nil)
15
+ if coordinates.is_a?(::Charta::Geometry)
16
+ coordinates
17
+ else
18
+ wrap(feature_factory.new_feature(coordinates, srs: srs, format: format))
19
+ end
20
+ end
21
+
22
+ def empty_geometry(srs)
23
+ wrap(feature_factory.empty_feature(srs))
24
+ end
25
+
26
+ protected
27
+
28
+ def wrap(feature)
29
+ case feature.geometry_type
30
+ when RGeo::Feature::Point
31
+ Point.new(feature)
32
+ when RGeo::Feature::LineString
33
+ LineString.new(feature)
34
+ when RGeo::Feature::Polygon
35
+ Polygon.new(feature)
36
+ when RGeo::Feature::MultiPolygon
37
+ MultiPolygon.new(feature)
38
+ when RGeo::Feature::GeometryCollection
39
+ GeometryCollection.new(feature)
40
+ else
41
+ Geometry.new(feature)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end