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
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ class SridProvider
6
+ SRS = {
7
+ WGS84: 4326,
8
+ CRS84: 4326,
9
+ RGF93: 2143
10
+ }.freeze
11
+
12
+ class << self
13
+ def build
14
+ new(SRS)
15
+ end
16
+ end
17
+
18
+ def initialize(srs)
19
+ @srs = srs
20
+ end
21
+
22
+ def find(srname_or_srid)
23
+ if srname_or_srid.to_s =~ /\Aurn:ogc:def:crs:.*\z/
24
+ x = srname_or_srid.split(':').last.upcase.to_sym
25
+ @srs[x] || x
26
+ elsif srname_or_srid.to_s =~ /\AEPSG::?(\d{4,5})\z/
27
+ srname_or_srid.split(':').last
28
+ elsif srname_or_srid.to_s =~ /\A\d+\z/
29
+ srname_or_srid.to_i
30
+ else
31
+ @srs[srname_or_srid] || srname_or_srid
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktPassthrough < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format.nil?
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ false
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ raise StandardError.new('Not implemented')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class EwktTransformerChain < EwktTransformer
7
+ class << self
8
+ def build
9
+ new(
10
+ Transformers::FromGeoJsonTransformer.new,
11
+ Transformers::FromWkbTransformer.new,
12
+ Transformers::FromGmlTransformer.new,
13
+ Transformers::FromKmlTransformer.new,
14
+ Transformers::EwktPassthrough.new
15
+ )
16
+ end
17
+ end
18
+
19
+ # @return [Array<EwktTransformer>]
20
+ attr_reader :transformers
21
+
22
+ def initialize(*transformers)
23
+ @transformers = transformers
24
+ end
25
+
26
+ # @return [Boolean]
27
+ def handles?(value, format:)
28
+ transformers.any? { |t| t.handles?(value, format: format) }
29
+ end
30
+
31
+ # @param [String, Hash] value
32
+ # @return [String] ewkt representation of value
33
+ def transform(value, srid: nil, format: nil)
34
+ transformer = transformers.detect { |t| t.handles?(value, format: format) }
35
+ raise TransformationError.new('Not handled') if transformer.nil?
36
+
37
+ transformer.transform(value, srid: srid, format: format)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromGeoJsonTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(Hash) || (value.is_a?(String) && Charta::GeoJSON.valid?(value)) # GeoJSON
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::GeoJSON.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromGmlTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format == 'gml' && Charta::GML.valid?(value)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::GML.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromKmlTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && format == 'kml' && Charta::KML.valid?(value)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ Charta::KML.new(value, srid).to_ewkt
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class FromWkbTransformer < EwktTransformer
7
+ # @return [Boolean]
8
+ def handles?(value, format:)
9
+ value.is_a?(String) && !!(value =~ /\A[A-F0-9]+\z/)
10
+ end
11
+
12
+ # @param [String, Hash] value
13
+ # @return [String] ewkt representation of value
14
+ def transform(value, srid: nil, format: nil)
15
+ if srid.nil?
16
+ Geometry.factory.parse_wkb(value)
17
+ else
18
+ RGeo::Geos.factory(srid: srid).parse_wkb(value)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Charta
4
+ module Factory
5
+ module Transformers
6
+ class TransformationError < StandardError
7
+ end
8
+ end
9
+ end
10
+ end
@@ -48,7 +48,10 @@ module Charta
48
48
  Coordinates.flatten hash
49
49
  end
50
50
 
51
- %i[object_to_ewkt feature_collection_to_ewkt geometry_collection_to_ewkt feature_to_ewkt point_to_ewkt line_string_to_ewkt polygon_to_ewkt multi_point_to_ewkt multi_line_string_to_ewkt multipolygon_to_ewkt multi_polygon_to_ewkt].each do |m|
51
+ %i[
52
+ object_to_ewkt feature_collection_to_ewkt geometry_collection_to_ewkt feature_to_ewkt point_to_ewkt line_string_to_ewkt
53
+ polygon_to_ewkt multi_point_to_ewkt multi_line_string_to_ewkt multipolygon_to_ewkt multi_polygon_to_ewkt
54
+ ].each do |m|
52
55
  define_method m do |*args|
53
56
  EwktSerializer.send m, *args
54
57
  end
@@ -97,6 +97,7 @@ module Charta
97
97
  other_geometry = Charta.new_geometry(other).transform(srid)
98
98
  return true if empty? && other_geometry.empty?
99
99
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?
100
+
100
101
  feature.equals?(other_geometry.feature)
101
102
  end
102
103
 
@@ -105,6 +106,7 @@ module Charta
105
106
  other_geometry = Charta.new_geometry(other).transform(srid)
106
107
  return true if empty? && other_geometry.empty?
107
108
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?
109
+
108
110
  !feature.equals?(other_geometry.feature)
109
111
  end
110
112
 
@@ -142,6 +144,7 @@ module Charta
142
144
  # of mass of the geometry as a POINT.
143
145
  def centroid
144
146
  return nil unless surface? && !feature.is_empty?
147
+
145
148
  point = feature.centroid
146
149
  [point.y, point.x]
147
150
  end
@@ -149,22 +152,23 @@ module Charta
149
152
  # Returns a POINT guaranteed to lie on the surface.
150
153
  def point_on_surface
151
154
  return nil unless surface?
155
+
152
156
  point = feature.point_on_surface
153
157
  [point.y, point.x]
154
158
  end
155
159
 
156
160
  def convert_to(new_type)
157
161
  case new_type
158
- when type then
159
- self
160
- when :multi_point then
161
- flatten_multi(:point)
162
- when :multi_line_string then
163
- flatten_multi(:line_string)
164
- when :multi_polygon then
165
- flatten_multi(:polygon)
166
- else
167
- self
162
+ when type
163
+ self
164
+ when :multi_point
165
+ flatten_multi(:point)
166
+ when :multi_line_string
167
+ flatten_multi(:line_string)
168
+ when :multi_polygon
169
+ flatten_multi(:polygon)
170
+ else
171
+ self
168
172
  end
169
173
  end
170
174
 
@@ -192,10 +196,12 @@ module Charta
192
196
  def transform(new_srid)
193
197
  return self if new_srid == srid
194
198
  raise 'Proj is not supported. Cannot tranform' unless RGeo::CoordSys::Proj4.supported?
199
+
195
200
  new_srid = Charta::SRS[new_srid] || new_srid
196
201
  database = self.class.srs_database
197
202
  new_proj_entry = database.get(new_srid)
198
203
  raise "Cannot find proj for SRID: #{new_srid}" if new_proj_entry.nil?
204
+
199
205
  new_feature = RGeo::CoordSys::Proj4.transform(
200
206
  database.get(srid).proj4,
201
207
  feature,
@@ -264,7 +270,7 @@ module Charta
264
270
  @feature = ::Charta::Geometry.from_ewkt(@ewkt)
265
271
  @properties = @options.dup if @options
266
272
  else
267
- raise StandardError, 'Invalid geometry (no feature, no EWKT)'
273
+ raise StandardError.new('Invalid geometry (no feature, no EWKT)')
268
274
  end
269
275
  end
270
276
  @feature.dup
@@ -273,7 +279,8 @@ module Charta
273
279
  alias to_rgeo feature
274
280
 
275
281
  def feature=(new_feature)
276
- raise ArgumentError, "Feature can't be nil" if new_feature.nil?
282
+ raise ArgumentError.new("Feature can't be nil") if new_feature.nil?
283
+
277
284
  @feature = new_feature
278
285
  end
279
286
 
@@ -292,6 +299,7 @@ module Charta
292
299
 
293
300
  def respond_to_missing?(name, include_private = false)
294
301
  return false if name == :init_with
302
+
295
303
  super
296
304
  end
297
305
 
@@ -302,11 +310,13 @@ module Charta
302
310
 
303
311
  def factory(srid = 4326)
304
312
  return projected_factory(srid) if srid.to_i == 4326
313
+
305
314
  geos_factory(srid)
306
315
  end
307
316
 
308
317
  def feature(ewkt_or_rgeo)
309
318
  return from_rgeo(ewkt_or_rgeo) if ewkt_or_rgeo.is_a? RGeo::Feature::Instance
319
+
310
320
  from_ewkt(ewkt_or_rgeo)
311
321
  end
312
322
 
@@ -1,10 +1,12 @@
1
1
  module Charta
2
2
  # Represent a Geometry with contains other geometries
3
3
  class GeometryCollection < Geometry
4
- def self.empty(srid = nil)
5
- srid = Charta.find_srid(srid.nil? ? :WGS84 : srid)
6
- feature = Charta.new_feature('GEOMETRYCOLLECTION EMPTY', srid)
7
- new(feature)
4
+ class << self
5
+ def empty(srid = nil)
6
+ srid = Charta.find_srid(srid.nil? ? :WGS84 : srid)
7
+ feature = Charta.new_feature('GEOMETRYCOLLECTION EMPTY', srid)
8
+ new(feature)
9
+ end
8
10
  end
9
11
 
10
12
  def to_json_feature_collection(collection_properties = [])
data/lib/charta/gml.rb CHANGED
@@ -83,6 +83,7 @@ module Charta
83
83
  'GEOMETRYCOLLECTION(' + gml.css("#{GML_PREFIX}|featureMember").collect do |feature|
84
84
  TAGS.collect do |tag|
85
85
  next if feature.css("#{GML_PREFIX}|#{tag}").empty?
86
+
86
87
  feature.css("#{GML_PREFIX}|#{tag}").collect do |fragment|
87
88
  object_to_ewkt(fragment, srid)
88
89
  end.compact.join(', ')
@@ -90,6 +91,7 @@ module Charta
90
91
  end.compact.join(', ') + ')'
91
92
  end
92
93
  end
94
+
93
95
  alias geometry_collection_to_ewkt document_to_ewkt
94
96
 
95
97
  def transform(data, from_srid, to_srid)
@@ -101,8 +103,9 @@ module Charta
101
103
 
102
104
  wkt = 'POLYGON(' + %w[outerBoundaryIs innerBoundaryIs].collect do |boundary|
103
105
  next if gml.css("#{GML_PREFIX}|#{boundary}").empty?
106
+
104
107
  gml.css("#{GML_PREFIX}|#{boundary}").collect do |hole|
105
- '(' + hole.css("#{GML_PREFIX}|coordinates").collect { |coords| coords.content.split(/\r\n|\n| /) }.flatten.reject(&:empty?).collect { |c| c.split ',' }.collect { |dimension| %(#{dimension.first} #{dimension[1]}) }.join(', ') + ')'
108
+ "(#{transform_coordinates(hole)})"
106
109
  end.join(', ')
107
110
  end.compact.join(', ') + ')'
108
111
 
@@ -115,6 +118,7 @@ module Charta
115
118
 
116
119
  def point_to_ewkt(gml, srid)
117
120
  return 'POINT EMPTY' if gml.css("#{GML_PREFIX}|coordinates").nil?
121
+
118
122
  wkt = 'POINT(' + gml.css("#{GML_PREFIX}|coordinates").collect { |coords| coords.content.split ',' }.flatten.join(' ') + ')'
119
123
 
120
124
  unless gml['srsName'].nil? || Charta.find_srid(gml['srsName']).to_s == srid.to_s
@@ -127,7 +131,7 @@ module Charta
127
131
  def line_string_to_ewkt(gml, srid)
128
132
  return 'LINESTRING EMPTY' if gml.css("#{GML_PREFIX}|coordinates").nil?
129
133
 
130
- wkt = 'LINESTRING(' + gml.css("#{GML_PREFIX}|coordinates").collect { |coords| coords.content.split(/\r\n|\n| /) }.flatten.reject(&:empty?).collect { |c| c.split ',' }.collect { |dimension| %(#{dimension.first} #{dimension[1]}) }.join(', ') + ')'
134
+ wkt = "LINESTRING(#{transform_coordinates(gml)})"
131
135
 
132
136
  unless gml['srsName'].nil? || Charta.find_srid(gml['srsName']).to_s == srid.to_s
133
137
  wkt = transform(wkt, Charta.find_srid(gml['srsName']), srid)
@@ -135,6 +139,18 @@ module Charta
135
139
 
136
140
  wkt
137
141
  end
142
+
143
+ private
144
+
145
+ def transform_coordinates(coordinates)
146
+ coordinates.css("#{GML_PREFIX}|coordinates")
147
+ .collect { |coords| coords.content.split(/\r\n|\n| /) }
148
+ .flatten
149
+ .reject(&:empty?)
150
+ .collect { |c| c.split ',' }
151
+ .collect { |dimension| %(#{dimension.first} #{dimension[1]}) }
152
+ .join(', ')
153
+ end
138
154
  end
139
155
  end
140
156
  end
@@ -63,30 +63,30 @@ class GmlImport
63
63
 
64
64
  private
65
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
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
89
90
  end
90
91
  end
91
- end
92
92
  end