charta 0.1.18 → 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 +21 -19
  3. data/lib/charta.rb +38 -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 +45 -25
  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 +84 -37
  30. data/.gitignore +0 -12
  31. data/.gitlab-ci.yml +0 -13
  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: 305d47070fc660134d7a4bed344db7efb555c9729a30e771af105a263c6aee01
4
- data.tar.gz: 4cfab59ae1d9f4034eb066bcf05e3a4c49b117604879e3e1e282a50e2c234f64
3
+ metadata.gz: 8f153424d966d80706e24233539f19c1efa2f7f5d013ac299046e51bd98e3ad8
4
+ data.tar.gz: '09fcff41f2a1f3d4a3cda3786c4a882f16b79cd551bda14c4083ebc351561956'
5
5
  SHA512:
6
- metadata.gz: 7cc82941e2062fa2309c294dc02b912528faf4a4893b34ee4a719a62ecd77422a1ff97d7c0255246dc4b9b014b2839bff6f7169e38d4be78cbb883d83352c26d
7
- data.tar.gz: 2193fbd5aa27ddca33cbd4ef3257168d2c567d1b8e4eb3def8ae2bcaed05e22aaeb82e8f6a17640955a7d92ff38835ab2d41a4f7f1e8dd01193db9fdab8dc31d
6
+ metadata.gz: 2a366f56215565b6183f990e5cdd10a829871f0280bf923aaad2e7ab3afca35432196b24d5b921a41de5a763efda7b2672be2b8c3f93003f78583829ab8222a5
7
+ data.tar.gz: b19fece238165742bf01a44d2f7b500801629f2325737b1a36c9997d4a5e42ed12555299454ca4ae03db477a4ef69e84fec85dd3e66970865bfe60a8771c09a9
data/charta.gemspec CHANGED
@@ -1,28 +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', '~> 0.6.0'
18
+ spec.add_dependency 'activesupport', '~> 5.0'
22
19
  spec.add_dependency 'json', '>= 1.8.0'
23
- spec.add_dependency 'rgeo-geojson', '~> 0.4.3'
24
- spec.add_development_dependency 'bundler', '~> 1.14'
25
- spec.add_development_dependency 'rake', '~> 10.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
+ spec.add_development_dependency 'bundler', '~> 2.0'
26
27
  spec.add_development_dependency 'minitest', '~> 5.0'
27
- spec.add_development_dependency 'byebug'
28
+ spec.add_development_dependency 'rake', '~> 12.0'
29
+ spec.add_development_dependency 'rubocop', '1.3.1'
28
30
  end
data/lib/charta.rb CHANGED
@@ -3,18 +3,16 @@
3
3
  require 'bigdecimal'
4
4
  require 'bigdecimal/util'
5
5
  require 'rgeo'
6
- require 'charta/coordinates'
7
- require 'charta/ewkt_serializer'
8
- require 'charta/geometry'
9
- require 'charta/geometry_collection'
10
- require 'charta/point'
11
- require 'charta/line_string'
12
- require 'charta/polygon'
13
- require 'charta/multi_polygon'
14
- require 'charta/bounding_box'
15
- require 'charta/geo_json'
16
- require 'charta/gml'
17
- require 'charta/kml'
6
+ require 'rgeo/proj4'
7
+ require 'zeitwerk'
8
+
9
+ loader = Zeitwerk::Loader.for_gem
10
+ loader.inflector.inflect(
11
+ 'geo_json' => 'GeoJSON',
12
+ 'gml' => 'GML',
13
+ 'kml' => 'KML'
14
+ )
15
+ loader.setup
18
16
 
19
17
  unless RGeo::CoordSys::Proj4.supported?
20
18
  puts "Proj4 is not supported. Some actions won't work"
@@ -29,75 +27,27 @@ module Charta
29
27
  }.freeze
30
28
 
31
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
32
45
  def new_feature(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
33
- geom_ewkt = nil
34
- if coordinates.is_a?(RGeo::Feature::Instance)
35
- return Geometry.feature(coordinates)
36
- elsif coordinates.is_a?(::Charta::Geometry)
37
- return coordinates
38
- elsif coordinates.to_s =~ /\A[[:space:]]*\z/
39
- geom_ewkt = empty_geometry(srs).to_ewkt
40
- elsif coordinates.is_a?(Hash) || (coordinates.is_a?(String) && ::Charta::GeoJSON.valid?(coordinates)) # GeoJSON
41
- srid = srs ? find_srid(srs) : :WGS84
42
- geom_ewkt = ::Charta::GeoJSON.new(coordinates, srid).to_ewkt
43
- elsif coordinates.is_a?(String)
44
- geom_ewkt = if coordinates =~ /\A[A-F0-9]+\z/ # WKB
45
- if srs && srid = find_srid(srs)
46
- generate_ewkt RGeo::Geos.factory(srid: srid).parse_wkb(coordinates)
47
- else
48
- generate_ewkt Geometry.factory.parse_wkb(coordinates)
49
- end
50
- elsif format == 'gml' && ::Charta::GML.valid?(coordinates)
51
- # required format 'cause kml geometries return empty instead of failing
52
- ::Charta::GML.new(coordinates, srid).to_ewkt
53
- elsif format == 'kml' && ::Charta::KML.valid?(coordinates)
54
- ::Charta::KML.new(coordinates).to_ewkt
55
- elsif coordinates =~ /^SRID\=\d+\;/i
56
- if feature = Geometry.feature(coordinates)
57
- generate_ewkt feature
58
- else
59
- Charta::GeometryCollection.empty.feature
60
- end
61
- else # WKT expected
62
- if srs && srid = find_srid(srs)
63
- begin
64
- f = RGeo::Geos.factory(srid: srid).parse_wkt(coordinates)
65
- rescue RGeo::Error::ParseError => e
66
- raise "Invalid EWKT (#{e.message}): #{coordinates}"
67
- end
68
- generate_ewkt f
69
- else
70
- generate_ewkt Geometry.feature(coordinates)
71
- end
72
- end
73
- else # Default for RGeo
74
- geom_ewkt = generate_ewkt coordinates
75
- end
76
- if geom_ewkt.to_s =~ /\A[[:space:]]*\z/
77
- raise ArgumentError, "Invalid data: coordinates=#{coordinates.inspect}, srid=#{srid.inspect}"
78
- end
79
- Geometry.feature(geom_ewkt)
46
+ default_feature_factory.new_feature(coordinates, srs: srs, format: format)
80
47
  end
81
48
 
82
49
  def new_geometry(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
83
- return coordinates if coordinates.is_a?(::Charta::Geometry)
84
- feature = Charta.new_feature(coordinates, srs, format, _flatten_collection, _options)
85
- type = feature.geometry_type
86
- geom = case type
87
- when RGeo::Feature::Point then
88
- Point.new(feature)
89
- when RGeo::Feature::LineString then
90
- LineString.new(feature)
91
- when RGeo::Feature::Polygon then
92
- Polygon.new(feature)
93
- when RGeo::Feature::MultiPolygon then
94
- MultiPolygon.new(feature)
95
- when RGeo::Feature::GeometryCollection then
96
- GeometryCollection.new(feature)
97
- else
98
- Geometry.new(feature)
99
- end
100
- geom
50
+ geometry_factory.new_geometry(coordinates, srs: srs, format: format)
101
51
  end
102
52
 
103
53
  def new_point(lat, lon, srid = 4326)
@@ -109,12 +59,18 @@ module Charta
109
59
  options[:srid] ||= new_geometry(points.first).srid if points.any?
110
60
  options[:srid] ||= 4326
111
61
 
112
- 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(', ')})"
113
69
  new_geometry(ewkt)
114
70
  end
115
71
 
116
72
  def empty_geometry(srid = :WGS84)
117
- GeometryCollection.empty(srid)
73
+ geometry_factory.empty_geometry(srid)
118
74
  end
119
75
 
120
76
  def generate_ewkt(feature)
@@ -141,23 +97,16 @@ module Charta
141
97
  end
142
98
 
143
99
  # Check and returns the SRID matching with srname or SRID.
100
+ # @deprecated
144
101
  def find_srid(srname_or_srid)
145
- if srname_or_srid.to_s =~ /\Aurn:ogc:def:crs:.*\z/
146
- x = srname_or_srid.split(':').last.upcase.to_sym
147
- SRS[x] || x
148
- elsif srname_or_srid.to_s =~ /\AEPSG::?(\d{4,5})\z/
149
- srname_or_srid.split(':').last
150
- elsif srname_or_srid.to_s =~ /\A\d+\z/
151
- srname_or_srid.to_i
152
- else
153
- SRS[srname_or_srid] || srname_or_srid
154
- end
102
+ Factory::SridProvider.build.find(srname_or_srid)
155
103
  end
156
104
 
157
105
  def from(format, data)
158
106
  unless respond_to?("from_#{format}")
159
107
  raise "Unknown format: #{format.inspect}"
160
108
  end
109
+
161
110
  send("from_#{format}", data)
162
111
  end
163
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