charta 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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