charta 0.2.2 → 0.4.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.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/charta.gemspec +21 -20
  3. data/lib/charta/bounding_box.rb +5 -1
  4. data/lib/charta/coordinates.rb +65 -0
  5. data/lib/charta/ewkt_serializer.rb +101 -0
  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 +12 -124
  20. data/lib/charta/geometry.rb +70 -16
  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 +6 -0
  27. data/lib/charta/polygon.rb +5 -0
  28. data/lib/charta/version.rb +1 -1
  29. data/lib/charta.rb +39 -87
  30. data/lib/rgeo/svg.rb +44 -44
  31. metadata +78 -44
  32. data/.gitignore +0 -11
  33. data/.gitlab-ci.yml +0 -14
  34. data/.travis.yml +0 -7
  35. data/CODE_OF_CONDUCT.md +0 -74
  36. data/Gemfile +0 -4
  37. data/LICENSE.txt +0 -21
  38. data/README.md +0 -44
  39. data/Rakefile +0 -10
@@ -7,12 +7,14 @@ module Charta
7
7
 
8
8
  def initialize(data, srid = :WGS84)
9
9
  srid ||= :WGS84
10
- @json = self.class.flatten(data.is_a?(Hash) ? data : JSON.parse(data))
10
+ @json = Coordinates.flatten(data.is_a?(Hash) ? data : JSON.parse(data))
11
11
  lsrid = @json['crs']['properties']['name'] if @json.is_a?(Hash) &&
12
12
  @json['crs'].is_a?(Hash) &&
13
13
  @json['crs']['properties'].is_a?(Hash)
14
14
  lsrid ||= srid
15
15
  @srid = ::Charta.find_srid(lsrid)
16
+
17
+ @json = Coordinates.normalize_4326_geometry(@json) if @srid.to_i == 4326
16
18
  end
17
19
 
18
20
  def geom
@@ -24,7 +26,7 @@ module Charta
24
26
  end
25
27
 
26
28
  def to_ewkt
27
- "SRID=#{@srid};" + self.class.object_to_ewkt(@json)
29
+ "SRID=#{srid};" + EwktSerializer.object_to_ewkt(@json)
28
30
  end
29
31
 
30
32
  def valid?
@@ -42,131 +44,17 @@ module Charta
42
44
  false
43
45
  end
44
46
 
45
- # Force coordinates to 2D
46
47
  def flatten(hash)
47
- if hash['type'] == 'FeatureCollection'
48
- flatten_feature_collection(hash)
49
- elsif hash['type'] == 'Feature'
50
- flatten_feature(hash)
51
- else
52
- flatten_geometry(hash)
53
- end
54
- end
55
-
56
- def flatten_feature_collection(hash)
57
- hash.merge('features' => hash['features'].map { |f| flatten_feature(f) })
58
- end
59
-
60
- def flatten_feature(hash)
61
- hash.merge('geometry' => flatten_geometry(hash['geometry']))
62
- end
63
-
64
- def flatten_geometry(hash)
65
- coordinates = hash['coordinates']
66
- flattened =
67
- case hash['type']
68
- when 'Point' then
69
- flatten_position(coordinates)
70
- when 'MultiPoint', 'LineString'
71
- coordinates.map { |p| flatten_position(p) }
72
- when 'MultiLineString', 'Polygon'
73
- coordinates.map { |l| l.map { |p| flatten_position(p) } }
74
- when 'MultiPolygon'
75
- coordinates.map { |m| m.map { |l| l.map { |p| flatten_position(p) } } }
76
- when 'GeometryCollection' then
77
- return hash.merge('geometries' => hash['geometries'].map { |g| flatten_geometry(g) })
78
- else
79
- raise StandardError, "Cannot handle: #{hash['type'].inspect}. In #{hash.inspect}"
80
- end
81
-
82
- hash.merge('coordinates' => flattened)
83
- end
84
-
85
- def flatten_position(position)
86
- position[0..1]
87
- end
88
-
89
- def object_to_ewkt(hash)
90
- type = hash[:type] || hash['type']
91
- send("#{type.gsub(/(.)([A-Z])/, '\1_\2').downcase}_to_ewkt", hash)
92
- end
93
-
94
- def feature_collection_to_ewkt(hash)
95
- return 'GEOMETRYCOLLECTION EMPTY' if hash['features'].nil?
96
- 'GEOMETRYCOLLECTION(' + hash['features'].collect do |feature|
97
- object_to_ewkt(feature)
98
- end.join(', ') + ')'
99
- end
100
-
101
- def geometry_collection_to_ewkt(hash)
102
- return 'GEOMETRYCOLLECTION EMPTY' if hash['geometries'].nil?
103
- 'GEOMETRYCOLLECTION(' + hash['geometries'].collect do |feature|
104
- object_to_ewkt(feature)
105
- end.join(', ') + ')'
106
- end
107
-
108
- def feature_to_ewkt(hash)
109
- object_to_ewkt(hash['geometry'])
110
- end
111
-
112
- def point_to_ewkt(hash)
113
- return 'POINT EMPTY' if hash['coordinates'].nil?
114
- 'POINT(' + hash['coordinates'].join(' ') + ')'
115
- end
116
-
117
- def line_string_to_ewkt(hash)
118
- return 'LINESTRING EMPTY' if hash['coordinates'].nil?
119
- 'LINESTRING(' + hash['coordinates'].collect do |point|
120
- point.join(' ')
121
- end.join(', ') + ')'
122
- end
123
-
124
- def polygon_to_ewkt(hash)
125
- return 'POLYGON EMPTY' if hash['coordinates'].nil?
126
- 'POLYGON(' + hash['coordinates'].collect do |hole|
127
- '(' + hole.collect do |point|
128
- point.join(' ')
129
- end.join(', ') + ')'
130
- end.join(', ') + ')'
131
- end
132
-
133
- def multi_point_to_ewkt(hash)
134
- return 'MULTIPOINT EMPTY' if hash['coordinates'].nil?
135
- 'MULTIPOINT(' + hash['coordinates'].collect do |point|
136
- '(' + point.join(' ') + ')'
137
- end.join(', ') + ')'
138
- end
139
-
140
- def multi_line_string_to_ewkt(hash)
141
- return 'MULTILINESTRING EMPTY' if hash['coordinates'].nil?
142
- 'MULTILINESTRING(' + hash['coordinates'].collect do |line|
143
- '(' + line.collect do |point|
144
- point.join(' ')
145
- end.join(', ') + ')'
146
- end.join(', ') + ')'
147
- end
148
-
149
- def multipolygon_to_ewkt(hash)
150
- return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
151
- 'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
152
- '(' + polygon.collect do |hole|
153
- '(' + hole.collect do |point|
154
- point.join(' ')
155
- end.join(', ') + ')'
156
- end.join(', ') + ')'
157
- end.join(', ') + ')'
48
+ Coordinates.flatten hash
158
49
  end
159
50
 
160
- # for PostGIS ST_ASGeoJSON compatibility
161
- def multi_polygon_to_ewkt(hash)
162
- return 'MULTIPOLYGON EMPTY' if hash['coordinates'].nil?
163
- 'MULTIPOLYGON(' + hash['coordinates'].collect do |polygon|
164
- '(' + polygon.collect do |hole|
165
- '(' + hole.collect do |point|
166
- point.join(' ')
167
- end.join(', ') + ')'
168
- end.join(', ') + ')'
169
- end.join(', ') + ')'
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|
55
+ define_method m do |*args|
56
+ EwktSerializer.send m, *args
57
+ end
170
58
  end
171
59
  end
172
60
  end
@@ -2,6 +2,7 @@ require 'json'
2
2
  require 'rgeo/geo_json'
3
3
  require 'rgeo/svg' # integrated lib for now
4
4
  require 'active_support/core_ext/module/delegation'
5
+ require 'victor' # for SVG
5
6
 
6
7
  module Charta
7
8
  # Represents a Geometry with SRID
@@ -63,16 +64,36 @@ module Charta
63
64
 
64
65
  alias to_ewkb to_binary
65
66
 
66
- # Pas bien compris le fonctionnement
67
+ # Generate SVG from geometry
68
+ # @param [Hash] options , the options for SVG object.
69
+ # @option options [Hash] :mode could be :stroke or :fill
70
+ # @option options [Hash] :color could be "orange", "red", "blue" or HTML color "#14TF15"
71
+ # @option options [Hash] :fill_opacity could be '0' to '100'
72
+ # @option options [Hash] :stroke_linecap could be 'round', 'square', 'butt'
73
+ # @option options [Hash] :stroke_linejoin default 'round'
74
+ # @option options [Hash] :stroke_width default '5%'
75
+ # @note more informations on https://developer.mozilla.org/fr/docs/Web/SVG/Tutorial/Fills_and_Strokes
76
+ # @return [String] the SVG image
67
77
  def to_svg(options = {})
68
- svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"'
69
- { preserve_aspect_ratio: 'xMidYMid meet',
70
- width: 180, height: 180,
71
- view_box: bounding_box.svg_view_box.join(' ') }.merge(options).each do |attr, value|
72
- svg << " #{Charta.camelcase(attr.to_s, :lower)}=\"#{value}\""
78
+ # set default options if not present
79
+ options[:mode] ||= :stroke
80
+ options[:color] ||= 'black'
81
+ options[:fill_opacity] ||= '100' # 0 to 100
82
+ options[:stroke_linecap] ||= 'butt' # round, square, butt
83
+ options[:stroke_linejoin] ||= 'round' #
84
+ options[:stroke_width] ||= '5%'
85
+
86
+ svg = Victor::SVG.new template: :html
87
+ svg.setup width: 180, height: 180, viewBox: bounding_box.svg_view_box.join(' ')
88
+ # return a stroke SVG with options
89
+ if options[:mode] == :stroke
90
+ svg.path d: to_svg_path, fill: 'none', stroke: options[:color], stroke_linecap: options[:stroke_linecap],
91
+ stroke_linejoin: options[:stroke_linejoin], stroke_width: options[:stroke_width]
92
+ # return a fill SVG with options
93
+ elsif options[:mode] == :fill
94
+ svg.path d: to_svg_path, fill: options[:color], fill_opacity: options[:fill_opacity]
73
95
  end
74
- svg << "><path d=\"#{to_svg_path}\"/></svg>"
75
- svg
96
+ svg.render
76
97
  end
77
98
 
78
99
  # Return the geometry as Scalar Vector Graphics (SVG) path data.
@@ -97,6 +118,7 @@ module Charta
97
118
  other_geometry = Charta.new_geometry(other).transform(srid)
98
119
  return true if empty? && other_geometry.empty?
99
120
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?
121
+
100
122
  feature.equals?(other_geometry.feature)
101
123
  end
102
124
 
@@ -105,17 +127,30 @@ module Charta
105
127
  other_geometry = Charta.new_geometry(other).transform(srid)
106
128
  return true if empty? && other_geometry.empty?
107
129
  return inspect == other_geometry.inspect if collection? && other_geometry.collection?
130
+
108
131
  !feature.equals?(other_geometry.feature)
109
132
  end
110
133
 
111
134
  # Returns true if Geometry is a Surface
112
135
  def surface?
113
- [RGeo::Feature::Polygon, RGeo::Feature::MultiPolygon].include? feature.geometry_type
136
+ if collection?
137
+ feature.any? { |geometry| Charta.new_geometry(geometry).surface? }
138
+ else
139
+ [RGeo::Feature::Polygon, RGeo::Feature::MultiPolygon].include? feature.geometry_type
140
+ end
114
141
  end
115
142
 
116
143
  # Returns area in unit corresponding to the SRS
117
144
  def area
118
- surface? ? feature.area : 0
145
+ if surface?
146
+ if collection?
147
+ feature.sum { |geometry| Charta.new_geometry(geometry).area }
148
+ else
149
+ feature.area
150
+ end
151
+ else
152
+ 0
153
+ end
119
154
  end
120
155
 
121
156
  # Returns true if this Geometry is an empty geometrycollection, polygon,
@@ -130,6 +165,7 @@ module Charta
130
165
  # of mass of the geometry as a POINT.
131
166
  def centroid
132
167
  return nil unless surface? && !feature.is_empty?
168
+
133
169
  point = feature.centroid
134
170
  [point.y, point.x]
135
171
  end
@@ -137,16 +173,23 @@ module Charta
137
173
  # Returns a POINT guaranteed to lie on the surface.
138
174
  def point_on_surface
139
175
  return nil unless surface?
176
+
140
177
  point = feature.point_on_surface
141
178
  [point.y, point.x]
142
179
  end
143
180
 
144
181
  def convert_to(new_type)
145
182
  case new_type
146
- when type then self
147
- when :multi_point then flatten_multi(:point)
148
- when :multi_line_string then flatten_multi(:line_string)
149
- when :multi_polygon then flatten_multi(:polygon)
183
+ when type
184
+ self
185
+ when :multi_point
186
+ flatten_multi(:point)
187
+ when :multi_line_string
188
+ flatten_multi(:line_string)
189
+ when :multi_polygon
190
+ flatten_multi(:polygon)
191
+ else
192
+ self
150
193
  end
151
194
  end
152
195
 
@@ -174,10 +217,12 @@ module Charta
174
217
  def transform(new_srid)
175
218
  return self if new_srid == srid
176
219
  raise 'Proj is not supported. Cannot tranform' unless RGeo::CoordSys::Proj4.supported?
220
+
177
221
  new_srid = Charta::SRS[new_srid] || new_srid
178
222
  database = self.class.srs_database
179
223
  new_proj_entry = database.get(new_srid)
180
224
  raise "Cannot find proj for SRID: #{new_srid}" if new_proj_entry.nil?
225
+
181
226
  new_feature = RGeo::CoordSys::Proj4.transform(
182
227
  database.get(srid).proj4,
183
228
  feature,
@@ -205,6 +250,11 @@ module Charta
205
250
  feature.intersection(other_geometry.feature)
206
251
  end
207
252
 
253
+ def intersects?(other)
254
+ other_geometry = Charta.new_geometry(other).transform(srid)
255
+ feature.intersects?(other_geometry.feature)
256
+ end
257
+
208
258
  def difference(other)
209
259
  other_geometry = Charta.new_geometry(other).transform(srid)
210
260
  feature.difference(other_geometry.feature)
@@ -241,7 +291,7 @@ module Charta
241
291
  @feature = ::Charta::Geometry.from_ewkt(@ewkt)
242
292
  @properties = @options.dup if @options
243
293
  else
244
- raise StandardError, 'Invalid geometry (no feature, no EWKT)'
294
+ raise StandardError.new('Invalid geometry (no feature, no EWKT)')
245
295
  end
246
296
  end
247
297
  @feature.dup
@@ -250,7 +300,8 @@ module Charta
250
300
  alias to_rgeo feature
251
301
 
252
302
  def feature=(new_feature)
253
- raise ArgumentError, "Feature can't be nil" if new_feature.nil?
303
+ raise ArgumentError.new("Feature can't be nil") if new_feature.nil?
304
+
254
305
  @feature = new_feature
255
306
  end
256
307
 
@@ -269,6 +320,7 @@ module Charta
269
320
 
270
321
  def respond_to_missing?(name, include_private = false)
271
322
  return false if name == :init_with
323
+
272
324
  super
273
325
  end
274
326
 
@@ -279,11 +331,13 @@ module Charta
279
331
 
280
332
  def factory(srid = 4326)
281
333
  return projected_factory(srid) if srid.to_i == 4326
334
+
282
335
  geos_factory(srid)
283
336
  end
284
337
 
285
338
  def feature(ewkt_or_rgeo)
286
339
  return from_rgeo(ewkt_or_rgeo) if ewkt_or_rgeo.is_a? RGeo::Feature::Instance
340
+
287
341
  from_ewkt(ewkt_or_rgeo)
288
342
  end
289
343
 
@@ -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
data/lib/charta/kml.rb CHANGED
@@ -22,7 +22,9 @@ module Charta
22
22
  end
23
23
 
24
24
  def to_ewkt
25
- "SRID=#{@srid};" + self.class.document_to_ewkt(@kml)
25
+ srid_part = @srid.nil? ? '' : "SRID=#{@srid};"
26
+
27
+ srid_part + self.class.document_to_ewkt(@kml)
26
28
  end
27
29
 
28
30
  def valid?
@@ -46,15 +48,18 @@ module Charta
46
48
 
47
49
  def document_to_ewkt(kml)
48
50
  return 'GEOMETRYCOLLECTION EMPTY' if kml.css('Document').nil?
51
+
49
52
  'GEOMETRYCOLLECTION(' + kml.css('Placemark').collect do |placemark|
50
53
  TAGS.collect do |tag|
51
54
  next if placemark.css(tag).empty?
55
+
52
56
  placemark.css(tag).collect do |fragment|
53
57
  object_to_ewkt(fragment)
54
58
  end.compact.join(', ')
55
59
  end.compact.join(', ')
56
60
  end.compact.join(', ') + ')'
57
61
  end
62
+
58
63
  alias geometry_collection_to_ewkt document_to_ewkt
59
64
 
60
65
  def feature_to_ewkt(kml)
@@ -63,13 +68,14 @@ module Charta
63
68
 
64
69
  def point_to_ewkt(kml)
65
70
  return 'POINT EMPTY' if kml.css('coordinates').nil?
71
+
66
72
  'POINT(' + kml.css('coordinates').collect { |coords| coords.content.split ',' }.flatten.join(' ') + ')'
67
73
  end
68
74
 
69
75
  def line_string_to_ewkt(kml)
70
76
  return 'LINESTRING EMPTY' if kml.css('coordinates').nil?
71
77
 
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(', ') + ')'
78
+ "LINESTRING(#{transform_coordinates(kml)})"
73
79
  end
74
80
 
75
81
  def polygon_to_ewkt(kml)
@@ -79,7 +85,7 @@ module Charta
79
85
  next if kml.css(boundary).empty?
80
86
 
81
87
  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(', ') + ')'
88
+ "(#{transform_coordinates(hole)})"
83
89
  end.join(', ')
84
90
  end.compact.join(', ') + ')'
85
91
  end
@@ -87,6 +93,18 @@ module Charta
87
93
  def multigeometry_to_ewkt(_kml)
88
94
  raise :not_implemented
89
95
  end
96
+
97
+ private
98
+
99
+ def transform_coordinates(coordinates)
100
+ coordinates.css('coordinates')
101
+ .collect { |coords| coords.content.split(/\r\n|\n| /) }
102
+ .flatten
103
+ .reject(&:empty?)
104
+ .collect { |c| c.split ',' }
105
+ .collect { |dimension| %(#{dimension.first} #{dimension[1]}) }
106
+ .join(', ')
107
+ end
90
108
  end
91
109
  end
92
110
  end
@@ -15,7 +15,7 @@ module Charta
15
15
 
16
16
  # Extract polygons ordered by 'PointOnSurface' position
17
17
  def polygons
18
- @polygons ||= feature._elements.map do |polygon|
18
+ @polygons ||= feature.elements.map do |polygon|
19
19
  Polygon.new(polygon)
20
20
  end || []
21
21
  end
data/lib/charta/point.rb CHANGED
@@ -10,5 +10,11 @@ module Charta
10
10
  feature.y
11
11
  end
12
12
  alias latitude y
13
+
14
+ def distance(point)
15
+ raise ArgumentError.new('wrong type: Charta::Point required') if point.class.name != 'Charta::Point'
16
+
17
+ to_rgeo.distance(point.to_rgeo)
18
+ end
13
19
  end
14
20
  end
@@ -8,5 +8,10 @@ module Charta
8
8
  end
9
9
  @exterior_ring
10
10
  end
11
+
12
+ def distance(point)
13
+ polygon_centroid = Charta.new_point(*centroid, 4326)
14
+ polygon_centroid.distance(point)
15
+ end
11
16
  end
12
17
  end
@@ -1,3 +1,3 @@
1
1
  module Charta
2
- VERSION = '0.2.2'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end