charta 0.2.0 → 0.3.1
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.
- checksums.yaml +5 -5
- data/charta.gemspec +21 -21
- data/lib/charta.rb +39 -87
- data/lib/charta/bounding_box.rb +4 -0
- data/lib/charta/coordinates.rb +65 -0
- data/lib/charta/ewkt_serializer.rb +101 -0
- data/lib/charta/factory/ewkt_feature_builder.rb +17 -0
- data/lib/charta/factory/feature_factory_base.rb +15 -0
- data/lib/charta/factory/simple_feature_factory.rb +50 -0
- data/lib/charta/factory/simple_geometry_factory.rb +46 -0
- data/lib/charta/factory/srid_provider.rb +36 -0
- data/lib/charta/factory/transformers/ewkt_passthrough.rb +20 -0
- data/lib/charta/factory/transformers/ewkt_transformer.rb +20 -0
- data/lib/charta/factory/transformers/ewkt_transformer_chain.rb +42 -0
- data/lib/charta/factory/transformers/from_geo_json_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_gml_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_kml_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_wkb_transformer.rb +24 -0
- data/lib/charta/factory/transformers/transformation_error.rb +10 -0
- data/lib/charta/geo_json.rb +12 -124
- data/lib/charta/geometry.rb +111 -68
- data/lib/charta/geometry_collection.rb +6 -4
- data/lib/charta/gml.rb +18 -2
- data/lib/charta/gml_import.rb +24 -24
- data/lib/charta/kml.rb +21 -3
- data/lib/charta/multi_polygon.rb +1 -1
- data/lib/charta/point.rb +6 -0
- data/lib/charta/polygon.rb +5 -0
- data/lib/charta/version.rb +1 -1
- data/lib/rgeo/svg.rb +44 -44
- metadata +76 -55
- data/.gitignore +0 -11
- data/.travis.yml +0 -7
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -21
- data/README.md +0 -44
- data/Rakefile +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a9634870840f818207264c46799dc53cf3e37bf3f3d119e85dc470405ebcb8d1
|
4
|
+
data.tar.gz: 6453c04a73201f197c869b37d18a6ff0c262c8545ced384a13ecee48568279e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 658472714de5dbe3a618839ddf36858884b6d28ab520bab2c5140514d0a287931b52aa1278110dc3979a3ed40b2bc0c7cb7e11a9450bff9767ae32180ebe24f8
|
7
|
+
data.tar.gz: 675ea3982c1d1bb3465f68e272fb995dde17cc61f5af81837346a7431fc79d1fc82dc0661eb2528aab2903808d6e0941d20923fa62142db25eafa95eb32a00f6
|
data/charta.gemspec
CHANGED
@@ -1,30 +1,30 @@
|
|
1
|
-
|
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
|
7
|
-
spec.version
|
8
|
-
spec.authors
|
9
|
-
spec.email
|
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
|
12
|
-
spec.
|
13
|
-
spec.
|
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 '
|
21
|
-
spec.add_dependency 'rgeo', '~> 1.0.0'
|
18
|
+
spec.add_dependency 'activesupport', '~> 5.0'
|
22
19
|
spec.add_dependency 'json', '>= 1.8.0'
|
23
|
-
spec.add_dependency '
|
24
|
-
spec.add_dependency 'rgeo
|
25
|
-
spec.add_dependency '
|
26
|
-
spec.
|
27
|
-
spec.
|
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'
|
28
27
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
29
|
-
spec.add_development_dependency '
|
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
@@ -1,17 +1,18 @@
|
|
1
1
|
# Gathers geomatic calculations
|
2
2
|
# Completes RGeo
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'bigdecimal/util'
|
3
5
|
require 'rgeo'
|
4
6
|
require 'rgeo/proj4'
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require 'charta/kml'
|
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
|
15
16
|
|
16
17
|
unless RGeo::CoordSys::Proj4.supported?
|
17
18
|
puts "Proj4 is not supported. Some actions won't work"
|
@@ -26,75 +27,27 @@ module Charta
|
|
26
27
|
}.freeze
|
27
28
|
|
28
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
|
29
45
|
def new_feature(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
|
30
|
-
|
31
|
-
if coordinates.is_a?(RGeo::Feature::Instance)
|
32
|
-
return Geometry.feature(coordinates)
|
33
|
-
elsif coordinates.is_a?(::Charta::Geometry)
|
34
|
-
return coordinates
|
35
|
-
elsif coordinates.to_s =~ /\A[[:space:]]*\z/
|
36
|
-
geom_ewkt = empty_geometry(srs).to_ewkt
|
37
|
-
elsif coordinates.is_a?(Hash) || (coordinates.is_a?(String) && ::Charta::GeoJSON.valid?(coordinates)) # GeoJSON
|
38
|
-
srid = srs ? find_srid(srs) : :WGS84
|
39
|
-
geom_ewkt = ::Charta::GeoJSON.new(coordinates, srid).to_ewkt
|
40
|
-
elsif coordinates.is_a?(String)
|
41
|
-
geom_ewkt = if coordinates =~ /\A[A-F0-9]+\z/ # WKB
|
42
|
-
if srs && srid = find_srid(srs)
|
43
|
-
generate_ewkt RGeo::Geos.factory(srid: srid).parse_wkb(coordinates)
|
44
|
-
else
|
45
|
-
generate_ewkt Geometry.factory.parse_wkb(coordinates)
|
46
|
-
end
|
47
|
-
elsif format == 'gml' && ::Charta::GML.valid?(coordinates)
|
48
|
-
# required format 'cause kml geometries return empty instead of failing
|
49
|
-
::Charta::GML.new(coordinates, srid).to_ewkt
|
50
|
-
elsif format == 'kml' && ::Charta::KML.valid?(coordinates)
|
51
|
-
::Charta::KML.new(coordinates).to_ewkt
|
52
|
-
elsif coordinates =~ /^SRID\=\d+\;/i
|
53
|
-
if feature = Geometry.feature(coordinates)
|
54
|
-
generate_ewkt feature
|
55
|
-
else
|
56
|
-
Charta::GeometryCollection.empty.feature
|
57
|
-
end
|
58
|
-
else # WKT expected
|
59
|
-
if srs && srid = find_srid(srs)
|
60
|
-
begin
|
61
|
-
f = RGeo::Geos.factory(srid: srid).parse_wkt(coordinates)
|
62
|
-
rescue RGeo::Error::ParseError => e
|
63
|
-
raise "Invalid EWKT (#{e.message}): #{coordinates}"
|
64
|
-
end
|
65
|
-
generate_ewkt f
|
66
|
-
else
|
67
|
-
generate_ewkt Geometry.feature(coordinates)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
else # Default for RGeo
|
71
|
-
geom_ewkt = generate_ewkt coordinates
|
72
|
-
end
|
73
|
-
if geom_ewkt.to_s =~ /\A[[:space:]]*\z/
|
74
|
-
raise ArgumentError, "Invalid data: coordinates=#{coordinates.inspect}, srid=#{srid.inspect}"
|
75
|
-
end
|
76
|
-
Geometry.feature(geom_ewkt)
|
46
|
+
default_feature_factory.new_feature(coordinates, srs: srs, format: format)
|
77
47
|
end
|
78
48
|
|
79
49
|
def new_geometry(coordinates, srs = nil, format = nil, _flatten_collection = true, _options = {})
|
80
|
-
|
81
|
-
feature = Charta.new_feature(coordinates, srs, format, _flatten_collection, _options)
|
82
|
-
type = feature.geometry_type
|
83
|
-
geom = case type
|
84
|
-
when RGeo::Feature::Point then
|
85
|
-
Point.new(feature)
|
86
|
-
when RGeo::Feature::LineString then
|
87
|
-
LineString.new(feature)
|
88
|
-
when RGeo::Feature::Polygon then
|
89
|
-
Polygon.new(feature)
|
90
|
-
when RGeo::Feature::MultiPolygon then
|
91
|
-
MultiPolygon.new(feature)
|
92
|
-
when RGeo::Feature::GeometryCollection then
|
93
|
-
GeometryCollection.new(feature)
|
94
|
-
else
|
95
|
-
Geometry.new(feature)
|
96
|
-
end
|
97
|
-
geom
|
50
|
+
geometry_factory.new_geometry(coordinates, srs: srs, format: format)
|
98
51
|
end
|
99
52
|
|
100
53
|
def new_point(lat, lon, srid = 4326)
|
@@ -106,12 +59,18 @@ module Charta
|
|
106
59
|
options[:srid] ||= new_geometry(points.first).srid if points.any?
|
107
60
|
options[:srid] ||= 4326
|
108
61
|
|
109
|
-
|
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(', ')})"
|
110
69
|
new_geometry(ewkt)
|
111
70
|
end
|
112
71
|
|
113
72
|
def empty_geometry(srid = :WGS84)
|
114
|
-
|
73
|
+
geometry_factory.empty_geometry(srid)
|
115
74
|
end
|
116
75
|
|
117
76
|
def generate_ewkt(feature)
|
@@ -138,23 +97,16 @@ module Charta
|
|
138
97
|
end
|
139
98
|
|
140
99
|
# Check and returns the SRID matching with srname or SRID.
|
100
|
+
# @deprecated
|
141
101
|
def find_srid(srname_or_srid)
|
142
|
-
|
143
|
-
x = srname_or_srid.split(':').last.upcase.to_sym
|
144
|
-
SRS[x] || x
|
145
|
-
elsif srname_or_srid.to_s =~ /\AEPSG::?(\d{4,5})\z/
|
146
|
-
srname_or_srid.split(':').last
|
147
|
-
elsif srname_or_srid.to_s =~ /\A\d+\z/
|
148
|
-
srname_or_srid.to_i
|
149
|
-
else
|
150
|
-
SRS[srname_or_srid] || srname_or_srid
|
151
|
-
end
|
102
|
+
Factory::SridProvider.build.find(srname_or_srid)
|
152
103
|
end
|
153
104
|
|
154
105
|
def from(format, data)
|
155
106
|
unless respond_to?("from_#{format}")
|
156
107
|
raise "Unknown format: #{format.inspect}"
|
157
108
|
end
|
109
|
+
|
158
110
|
send("from_#{format}", data)
|
159
111
|
end
|
160
112
|
|
data/lib/charta/bounding_box.rb
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Charta
|
2
|
+
module Coordinates
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# Force coordinates to 2D
|
6
|
+
def flatten(hash)
|
7
|
+
map_coordinates(hash) { |position| position[0..1] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def map_coordinates(hash, &block)
|
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
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def normalize_4326_geometry(json)
|
22
|
+
map_coordinates json do |(x, y)|
|
23
|
+
[((x + 180.to_d) % 360.to_d) - 180.to_d, ((y + 90.to_d) % 180.to_d) - 90.to_d]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def map_feature_collection_coordinates(hash, &block)
|
30
|
+
hash.merge 'features' => hash['features'].map { |feature| map_feature_coordinates feature, &block }
|
31
|
+
end
|
32
|
+
|
33
|
+
def map_feature_coordinates(hash, &block)
|
34
|
+
hash.merge 'geometry' => map_geometry_coordinates(hash['geometry'], &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def map_geometry_coordinates(hash, &block)
|
38
|
+
if hash['type'] == 'GeometryCollection'
|
39
|
+
map_geometry_collection_coordinates hash, &block
|
40
|
+
else
|
41
|
+
coordinates = hash['coordinates']
|
42
|
+
mapped =
|
43
|
+
case hash['type']
|
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
|
+
end
|
55
|
+
|
56
|
+
hash.merge 'coordinates' => mapped
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def map_geometry_collection_coordinates(hash, &block)
|
61
|
+
hash.merge 'geometries' => hash['geometries'].map { |geometry| map_geometry_coordinates(geometry, &block) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Charta
|
2
|
+
module EwktSerializer
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def object_to_ewkt(hash)
|
6
|
+
type = hash[:type] || hash['type']
|
7
|
+
send("#{type.gsub(/(.)([A-Z])/, '\1_\2').downcase}_to_ewkt", hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def feature_collection_to_ewkt(hash)
|
13
|
+
return 'GEOMETRYCOLLECTION EMPTY' if hash['features'].nil?
|
14
|
+
|
15
|
+
'GEOMETRYCOLLECTION(' + hash['features'].collect do |feature|
|
16
|
+
object_to_ewkt(feature)
|
17
|
+
end.join(', ') + ')'
|
18
|
+
end
|
19
|
+
|
20
|
+
def geometry_collection_to_ewkt(hash)
|
21
|
+
return 'GEOMETRYCOLLECTION EMPTY' if hash['geometries'].nil?
|
22
|
+
|
23
|
+
'GEOMETRYCOLLECTION(' + hash['geometries'].collect do |feature|
|
24
|
+
object_to_ewkt(feature)
|
25
|
+
end.join(', ') + ')'
|
26
|
+
end
|
27
|
+
|
28
|
+
def feature_to_ewkt(hash)
|
29
|
+
object_to_ewkt(hash['geometry'])
|
30
|
+
end
|
31
|
+
|
32
|
+
def point_to_ewkt(hash)
|
33
|
+
return 'POINT EMPTY' if hash['coordinates'].nil?
|
34
|
+
|
35
|
+
'POINT(' + hash['coordinates'].join(' ') + ')'
|
36
|
+
end
|
37
|
+
|
38
|
+
def line_string_to_ewkt(hash)
|
39
|
+
return 'LINESTRING EMPTY' if hash['coordinates'].nil?
|
40
|
+
|
41
|
+
'LINESTRING(' + hash['coordinates'].collect do |point|
|
42
|
+
point.join(' ')
|
43
|
+
end.join(', ') + ')'
|
44
|
+
end
|
45
|
+
|
46
|
+
def polygon_to_ewkt(hash)
|
47
|
+
return 'POLYGON EMPTY' if hash['coordinates'].nil?
|
48
|
+
|
49
|
+
'POLYGON(' + hash['coordinates'].collect do |hole|
|
50
|
+
'(' + hole.collect do |point|
|
51
|
+
point.join(' ')
|
52
|
+
end.join(', ') + ')'
|
53
|
+
end.join(', ') + ')'
|
54
|
+
end
|
55
|
+
|
56
|
+
def multi_point_to_ewkt(hash)
|
57
|
+
return 'MULTIPOINT EMPTY' if hash['coordinates'].nil?
|
58
|
+
|
59
|
+
'MULTIPOINT(' + hash['coordinates'].collect do |point|
|
60
|
+
'(' + point.join(' ') + ')'
|
61
|
+
end.join(', ') + ')'
|
62
|
+
end
|
63
|
+
|
64
|
+
def multi_line_string_to_ewkt(hash)
|
65
|
+
return 'MULTILINESTRING EMPTY' if hash['coordinates'].nil?
|
66
|
+
|
67
|
+
'MULTILINESTRING(' + hash['coordinates'].collect do |line|
|
68
|
+
'(' + line.collect do |point|
|
69
|
+
point.join(' ')
|
70
|
+
end.join(', ') + ')'
|
71
|
+
end.join(', ') + ')'
|
72
|
+
end
|
73
|
+
|
74
|
+
def multipolygon_to_ewkt(hash)
|
75
|
+
return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
|
76
|
+
|
77
|
+
'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
|
78
|
+
'(' + polygon.collect do |hole|
|
79
|
+
'(' + hole.collect do |point|
|
80
|
+
point.join(' ')
|
81
|
+
end.join(', ') + ')'
|
82
|
+
end.join(', ') + ')'
|
83
|
+
end.join(', ') + ')'
|
84
|
+
end
|
85
|
+
|
86
|
+
# for PostGIS ST_ASGeoJSON compatibility
|
87
|
+
def multi_polygon_to_ewkt(hash)
|
88
|
+
return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
|
89
|
+
|
90
|
+
'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
|
91
|
+
'(' + polygon.collect do |hole|
|
92
|
+
'(' + hole.collect do |point|
|
93
|
+
point.join(' ')
|
94
|
+
end.join(', ') + ')'
|
95
|
+
end.join(', ') + ')'
|
96
|
+
end.join(', ') + ')'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
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
|