charta 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +10 -0
- data/charta.gemspec +30 -0
- data/lib/charta.rb +176 -0
- data/lib/charta/bounding_box.rb +28 -0
- data/lib/charta/geo_json.rb +168 -0
- data/lib/charta/geojson_import.rb +30 -0
- data/lib/charta/geometry.rb +278 -0
- data/lib/charta/geometry_collection.rb +9 -0
- data/lib/charta/gml.rb +140 -0
- data/lib/charta/gml_import.rb +92 -0
- data/lib/charta/kml.rb +92 -0
- data/lib/charta/line_string.rb +22 -0
- data/lib/charta/multi_polygon.rb +28 -0
- data/lib/charta/point.rb +14 -0
- data/lib/charta/polygon.rb +12 -0
- data/lib/charta/version.rb +3 -0
- data/lib/rgeo/svg.rb +69 -0
- metadata +179 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class GmlImport
|
4
|
+
def initialize(data)
|
5
|
+
@shapes = nil
|
6
|
+
@xml = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?
|
10
|
+
shapes
|
11
|
+
geometries = as_geojson || {}
|
12
|
+
|
13
|
+
!geometries.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
def sanitize(xml)
|
17
|
+
xml.to_s.split.join(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
def shapes(options = {})
|
21
|
+
options[:to] ||= ''
|
22
|
+
|
23
|
+
f = sanitize @xml
|
24
|
+
|
25
|
+
doc = Nokogiri::XML(f) do |config|
|
26
|
+
config.options = Nokogiri::XML::ParseOptions::NOBLANKS
|
27
|
+
end
|
28
|
+
|
29
|
+
@shapes = doc.root
|
30
|
+
|
31
|
+
if options[:to].equal? :xml
|
32
|
+
@shapes = @shapes.to_xml
|
33
|
+
elsif options[:to].equal? :string
|
34
|
+
@shapes = @shapes.to_s
|
35
|
+
else
|
36
|
+
@shapes
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def as_geojson
|
41
|
+
geojson_features_collection = {}
|
42
|
+
geojson_features = []
|
43
|
+
|
44
|
+
if @shapes.is_a? Nokogiri::XML::Node
|
45
|
+
|
46
|
+
geojson_features << featurize(@shapes)
|
47
|
+
|
48
|
+
elsif @shapes.is_a? Nokogiri::XML::NodeSet
|
49
|
+
|
50
|
+
@shapes.each do |node|
|
51
|
+
geojson_features << featurize(node)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
geojson_features_collection = {
|
57
|
+
type: 'FeatureCollection',
|
58
|
+
features: geojson_features
|
59
|
+
}
|
60
|
+
|
61
|
+
geojson_features_collection
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def featurize(node)
|
67
|
+
if node.element? && node.xpath('.//gml:Polygon')
|
68
|
+
geojson_feature = {}
|
69
|
+
|
70
|
+
geometry = node.xpath('.//gml:Polygon')
|
71
|
+
geometry.first['srsName'] = 'EPSG:2154'
|
72
|
+
|
73
|
+
if ::Charta::GML.valid?(geometry)
|
74
|
+
|
75
|
+
# properties
|
76
|
+
id = (Time.zone.now.to_i.to_s + Time.zone.now.usec.to_s)
|
77
|
+
|
78
|
+
geojson_feature = {
|
79
|
+
type: 'Feature',
|
80
|
+
properties: {
|
81
|
+
internal_id: id
|
82
|
+
}.reject { |_, v| v.nil? },
|
83
|
+
geometry: ::Charta.new_geometry(geometry.to_xml, nil, 'gml').transform(:WGS84).to_geojson
|
84
|
+
}.reject { |_, v| v.nil? }
|
85
|
+
|
86
|
+
return geojson_feature
|
87
|
+
else
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/charta/kml.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Charta
|
4
|
+
# Represents a Geometry with SRID
|
5
|
+
class KML
|
6
|
+
attr_reader :srid
|
7
|
+
|
8
|
+
TAGS = %w[Point LineString Polygon MultiGeometry].freeze
|
9
|
+
|
10
|
+
def initialize(data, srid = :WGS84)
|
11
|
+
@kml = if data.is_a? String
|
12
|
+
|
13
|
+
Nokogiri::XML(data.to_s.split.join(' ')) do |config|
|
14
|
+
config.options = Nokogiri::XML::ParseOptions::NOBLANKS
|
15
|
+
end
|
16
|
+
|
17
|
+
else
|
18
|
+
# Nokogiri::XML::Document expected
|
19
|
+
data
|
20
|
+
end
|
21
|
+
@srid = Charta.find_srid(srid)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_ewkt
|
25
|
+
"SRID=#{@srid};" + self.class.document_to_ewkt(@kml)
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid?
|
29
|
+
to_ewkt
|
30
|
+
true
|
31
|
+
# rescue
|
32
|
+
# false
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
# Test is given data is a valid KML
|
37
|
+
def valid?(data, srid = :WGS84)
|
38
|
+
new(data, srid).valid?
|
39
|
+
# rescue
|
40
|
+
# false
|
41
|
+
end
|
42
|
+
|
43
|
+
def object_to_ewkt(fragment)
|
44
|
+
send("#{Charta.underscore(fragment.name)}_to_ewkt", fragment)
|
45
|
+
end
|
46
|
+
|
47
|
+
def document_to_ewkt(kml)
|
48
|
+
return 'GEOMETRYCOLLECTION EMPTY' if kml.css('Document').nil?
|
49
|
+
'GEOMETRYCOLLECTION(' + kml.css('Placemark').collect do |placemark|
|
50
|
+
TAGS.collect do |tag|
|
51
|
+
next if placemark.css(tag).empty?
|
52
|
+
placemark.css(tag).collect do |fragment|
|
53
|
+
object_to_ewkt(fragment)
|
54
|
+
end.compact.join(', ')
|
55
|
+
end.compact.join(', ')
|
56
|
+
end.compact.join(', ') + ')'
|
57
|
+
end
|
58
|
+
alias geometry_collection_to_ewkt document_to_ewkt
|
59
|
+
|
60
|
+
def feature_to_ewkt(kml)
|
61
|
+
object_to_ewkt(kml)
|
62
|
+
end
|
63
|
+
|
64
|
+
def point_to_ewkt(kml)
|
65
|
+
return 'POINT EMPTY' if kml.css('coordinates').nil?
|
66
|
+
'POINT(' + kml.css('coordinates').collect { |coords| coords.content.split ',' }.flatten.join(' ') + ')'
|
67
|
+
end
|
68
|
+
|
69
|
+
def line_string_to_ewkt(kml)
|
70
|
+
return 'LINESTRING EMPTY' if kml.css('coordinates').nil?
|
71
|
+
|
72
|
+
'LINESTRING(' + kml.css('coordinates').collect { |coords| coords.content.split(/\r\n|\n| /) }.flatten.reject(&:empty?).collect { |c| c.split ',' }.collect { |dimension| %(#{dimension.first} #{dimension[1]}) }.join(', ') + ')'
|
73
|
+
end
|
74
|
+
|
75
|
+
def polygon_to_ewkt(kml)
|
76
|
+
return 'POLYGON EMPTY' if kml.css('coordinates').nil?
|
77
|
+
|
78
|
+
'POLYGON(' + %w[outerBoundaryIs innerBoundaryIs].collect do |boundary|
|
79
|
+
next if kml.css(boundary).empty?
|
80
|
+
|
81
|
+
kml.css(boundary).collect do |hole|
|
82
|
+
'(' + hole.css('coordinates').collect { |coords| coords.content.split(/\r\n|\n| /) }.flatten.reject(&:empty?).collect { |c| c.split ',' }.collect { |dimension| %(#{dimension.first} #{dimension[1]}) }.join(', ') + ')'
|
83
|
+
end.join(', ')
|
84
|
+
end.compact.join(', ') + ')'
|
85
|
+
end
|
86
|
+
|
87
|
+
def multigeometry_to_ewkt(_kml)
|
88
|
+
raise :not_implemented
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Charta
|
2
|
+
# Represent a Geometry which contains points in a line string.
|
3
|
+
class LineString < Geometry
|
4
|
+
# Browse each point
|
5
|
+
def each_point(&block)
|
6
|
+
if block.arity == 1
|
7
|
+
points.each(&block)
|
8
|
+
elsif block.arity == 2
|
9
|
+
points.each_with_index(&block)
|
10
|
+
else
|
11
|
+
raise 'Cannot browse each point without parameter'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def points
|
16
|
+
@points ||= feature.points.map do |point|
|
17
|
+
generator = RGeo::WKRep::WKTGenerator.new(tag_format: :ewkt, emit_ewkt_srid: true)
|
18
|
+
Point.new(generator.generate(point))
|
19
|
+
end || []
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Charta
|
2
|
+
# Represent a Geometry with contains only polygons
|
3
|
+
class MultiPolygon < GeometryCollection
|
4
|
+
def each_polygon(&block)
|
5
|
+
if block.arity == 1
|
6
|
+
polygons.each(&block)
|
7
|
+
elsif block.arity == 2
|
8
|
+
polygons.each_with_index do |polygon, index|
|
9
|
+
yield polygon, index + 1
|
10
|
+
end
|
11
|
+
else
|
12
|
+
raise 'Cannot browse each polygon without parameter'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Extract polygons ordered by 'PointOnSurface' position
|
17
|
+
def polygons
|
18
|
+
unless defined? @polygons
|
19
|
+
@polygons = []
|
20
|
+
feature.each do |polygon|
|
21
|
+
generator = RGeo::WKRep::WKTGenerator.new(tag_format: :ewkt, emit_ewkt_srid: true)
|
22
|
+
@polygons << Polygon.new(generator.generate(polygon))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@polygons
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/charta/point.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Charta
|
2
|
+
# Represent a Geometry with contains only polygons
|
3
|
+
class Polygon < Geometry
|
4
|
+
def exterior_ring
|
5
|
+
unless defined? @exterior_ring
|
6
|
+
generator = RGeo::WKRep::WKTGenerator.new(tag_format: :ewkt, emit_ewkt_srid: true)
|
7
|
+
@exterior_ring = Charta.new_geometry(generator.generate(feature.exterior_ring))
|
8
|
+
end
|
9
|
+
@exterior_ring
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/rgeo/svg.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module RGeo
|
2
|
+
module SVG
|
3
|
+
class << self
|
4
|
+
def encode(feature)
|
5
|
+
send('encode_' + Charta.underscore(feature.geometry_type.type_name), feature)
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def encode_point(feature)
|
11
|
+
'M' + coordinates(feature)
|
12
|
+
end
|
13
|
+
|
14
|
+
def encode_multi_point(feature)
|
15
|
+
points = []
|
16
|
+
feature.each do |point|
|
17
|
+
points << encode_point(point)
|
18
|
+
end
|
19
|
+
points.join(' ')
|
20
|
+
end
|
21
|
+
|
22
|
+
def encode_line_string(feature)
|
23
|
+
points = []
|
24
|
+
feature.points.each do |point|
|
25
|
+
points << coordinates(point)
|
26
|
+
end
|
27
|
+
'M' + points.join('L')
|
28
|
+
end
|
29
|
+
|
30
|
+
def encode_multi_line_string(feature)
|
31
|
+
line_strings = []
|
32
|
+
feature.each do |line_string|
|
33
|
+
line_strings << encode_line_string(line_string)
|
34
|
+
end
|
35
|
+
line_strings.join(' ')
|
36
|
+
end
|
37
|
+
|
38
|
+
def encode_polygon(feature)
|
39
|
+
rings = []
|
40
|
+
# TODO: Optimize useless last point repetition
|
41
|
+
rings << encode_line_string(feature.exterior_ring) + 'Z'
|
42
|
+
feature.interior_rings.each do |ring|
|
43
|
+
rings << encode_line_string(ring) + 'Z'
|
44
|
+
end
|
45
|
+
rings.join(' ')
|
46
|
+
end
|
47
|
+
|
48
|
+
def encode_multi_polygon(feature)
|
49
|
+
polygons = []
|
50
|
+
feature.each do |polygon|
|
51
|
+
polygons << encode_polygon(polygon)
|
52
|
+
end
|
53
|
+
polygons.join(' ')
|
54
|
+
end
|
55
|
+
|
56
|
+
def encode_geometry_collection(feature)
|
57
|
+
geometries = []
|
58
|
+
feature.each do |geometry|
|
59
|
+
geometries << encode(geometry)
|
60
|
+
end
|
61
|
+
geometries.join(' ')
|
62
|
+
end
|
63
|
+
|
64
|
+
def coordinates(feature)
|
65
|
+
feature.x.to_s + ',' + feature.y.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: charta
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brice TEXIER
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.7.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.7.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rgeo
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.8.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rgeo-geojson
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.4.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.4.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.14'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.14'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- brice@ekylibre.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".travis.yml"
|
134
|
+
- CODE_OF_CONDUCT.md
|
135
|
+
- Gemfile
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- charta.gemspec
|
140
|
+
- lib/charta.rb
|
141
|
+
- lib/charta/bounding_box.rb
|
142
|
+
- lib/charta/geo_json.rb
|
143
|
+
- lib/charta/geojson_import.rb
|
144
|
+
- lib/charta/geometry.rb
|
145
|
+
- lib/charta/geometry_collection.rb
|
146
|
+
- lib/charta/gml.rb
|
147
|
+
- lib/charta/gml_import.rb
|
148
|
+
- lib/charta/kml.rb
|
149
|
+
- lib/charta/line_string.rb
|
150
|
+
- lib/charta/multi_polygon.rb
|
151
|
+
- lib/charta/point.rb
|
152
|
+
- lib/charta/polygon.rb
|
153
|
+
- lib/charta/version.rb
|
154
|
+
- lib/rgeo/svg.rb
|
155
|
+
homepage: https://github.com/ekylibre/charta
|
156
|
+
licenses:
|
157
|
+
- MIT
|
158
|
+
metadata: {}
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubyforge_project:
|
175
|
+
rubygems_version: 2.5.2
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: Simple tool over geos and co
|
179
|
+
test_files: []
|