charta 0.1.18 → 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 +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