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.
@@ -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
@@ -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
@@ -0,0 +1,14 @@
1
+ module Charta
2
+ # Represent a Point
3
+ class Point < Geometry
4
+ def x
5
+ feature.x
6
+ end
7
+ alias longitude x
8
+
9
+ def y
10
+ feature.y
11
+ end
12
+ alias latitude y
13
+ end
14
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Charta
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -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: []