charta 0.2.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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