charta 0.2.0 → 0.3.1
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 +5 -5
- data/charta.gemspec +21 -21
- data/lib/charta.rb +39 -87
- data/lib/charta/bounding_box.rb +4 -0
- data/lib/charta/coordinates.rb +65 -0
- data/lib/charta/ewkt_serializer.rb +101 -0
- data/lib/charta/factory/ewkt_feature_builder.rb +17 -0
- data/lib/charta/factory/feature_factory_base.rb +15 -0
- data/lib/charta/factory/simple_feature_factory.rb +50 -0
- data/lib/charta/factory/simple_geometry_factory.rb +46 -0
- data/lib/charta/factory/srid_provider.rb +36 -0
- data/lib/charta/factory/transformers/ewkt_passthrough.rb +20 -0
- data/lib/charta/factory/transformers/ewkt_transformer.rb +20 -0
- data/lib/charta/factory/transformers/ewkt_transformer_chain.rb +42 -0
- data/lib/charta/factory/transformers/from_geo_json_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_gml_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_kml_transformer.rb +20 -0
- data/lib/charta/factory/transformers/from_wkb_transformer.rb +24 -0
- data/lib/charta/factory/transformers/transformation_error.rb +10 -0
- data/lib/charta/geo_json.rb +12 -124
- data/lib/charta/geometry.rb +111 -68
- data/lib/charta/geometry_collection.rb +6 -4
- data/lib/charta/gml.rb +18 -2
- data/lib/charta/gml_import.rb +24 -24
- data/lib/charta/kml.rb +21 -3
- data/lib/charta/multi_polygon.rb +1 -1
- data/lib/charta/point.rb +6 -0
- data/lib/charta/polygon.rb +5 -0
- data/lib/charta/version.rb +1 -1
- data/lib/rgeo/svg.rb +44 -44
- metadata +76 -55
- data/.gitignore +0 -11
- data/.travis.yml +0 -7
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -21
- data/README.md +0 -44
- data/Rakefile +0 -10
data/lib/charta/geometry.rb
CHANGED
@@ -6,8 +6,6 @@ require 'active_support/core_ext/module/delegation'
|
|
6
6
|
module Charta
|
7
7
|
# Represents a Geometry with SRID
|
8
8
|
class Geometry
|
9
|
-
delegate_missing_to :to_rgeo
|
10
|
-
|
11
9
|
def initialize(feature, properties = {})
|
12
10
|
self.feature = feature
|
13
11
|
@properties = properties
|
@@ -36,16 +34,12 @@ module Charta
|
|
36
34
|
feature.srid.to_i
|
37
35
|
end
|
38
36
|
|
39
|
-
# Returns the underlaying object managed by Charta: the RGeo feature
|
40
|
-
def to_rgeo
|
41
|
-
feature
|
42
|
-
end
|
43
|
-
|
44
37
|
# Returns the Well-Known Text (WKT) representation of the geometry/geography
|
45
38
|
# without SRID metadata
|
46
39
|
def to_text
|
47
40
|
feature.as_text.match(/\ASRID=.*;(.*)/)[1]
|
48
41
|
end
|
42
|
+
|
49
43
|
alias as_text to_text
|
50
44
|
alias to_wkt to_text
|
51
45
|
|
@@ -53,6 +47,7 @@ module Charta
|
|
53
47
|
def to_ewkt
|
54
48
|
Charta.generate_ewkt(feature).to_s
|
55
49
|
end
|
50
|
+
|
56
51
|
alias to_s to_ewkt
|
57
52
|
|
58
53
|
def ewkt
|
@@ -65,6 +60,7 @@ module Charta
|
|
65
60
|
generator = RGeo::WKRep::WKBGenerator.new(tag_format: :ewkbt, emit_ewkbt_srid: true)
|
66
61
|
generator.generate(feature)
|
67
62
|
end
|
63
|
+
|
68
64
|
alias to_ewkb to_binary
|
69
65
|
|
70
66
|
# Pas bien compris le fonctionnement
|
@@ -88,6 +84,7 @@ module Charta
|
|
88
84
|
def to_geojson
|
89
85
|
to_json_object.to_json
|
90
86
|
end
|
87
|
+
|
91
88
|
alias to_json to_geojson
|
92
89
|
|
93
90
|
# Returns object in JSON (Hash)
|
@@ -100,6 +97,7 @@ module Charta
|
|
100
97
|
other_geometry = Charta.new_geometry(other).transform(srid)
|
101
98
|
return true if empty? && other_geometry.empty?
|
102
99
|
return inspect == other_geometry.inspect if collection? && other_geometry.collection?
|
100
|
+
|
103
101
|
feature.equals?(other_geometry.feature)
|
104
102
|
end
|
105
103
|
|
@@ -108,17 +106,30 @@ module Charta
|
|
108
106
|
other_geometry = Charta.new_geometry(other).transform(srid)
|
109
107
|
return true if empty? && other_geometry.empty?
|
110
108
|
return inspect == other_geometry.inspect if collection? && other_geometry.collection?
|
109
|
+
|
111
110
|
!feature.equals?(other_geometry.feature)
|
112
111
|
end
|
113
112
|
|
114
113
|
# Returns true if Geometry is a Surface
|
115
114
|
def surface?
|
116
|
-
|
115
|
+
if collection?
|
116
|
+
feature.any? { |geometry| Charta.new_geometry(geometry).surface? }
|
117
|
+
else
|
118
|
+
[RGeo::Feature::Polygon, RGeo::Feature::MultiPolygon].include? feature.geometry_type
|
119
|
+
end
|
117
120
|
end
|
118
121
|
|
119
122
|
# Returns area in unit corresponding to the SRS
|
120
123
|
def area
|
121
|
-
surface?
|
124
|
+
if surface?
|
125
|
+
if collection?
|
126
|
+
feature.sum { |geometry| Charta.new_geometry(geometry).area }
|
127
|
+
else
|
128
|
+
feature.area
|
129
|
+
end
|
130
|
+
else
|
131
|
+
0
|
132
|
+
end
|
122
133
|
end
|
123
134
|
|
124
135
|
# Returns true if this Geometry is an empty geometrycollection, polygon,
|
@@ -126,12 +137,14 @@ module Charta
|
|
126
137
|
def empty?
|
127
138
|
feature.is_empty?
|
128
139
|
end
|
140
|
+
|
129
141
|
alias blank? empty?
|
130
142
|
|
131
143
|
# Computes the geometric center of a geometry, or equivalently, the center
|
132
144
|
# of mass of the geometry as a POINT.
|
133
145
|
def centroid
|
134
146
|
return nil unless surface? && !feature.is_empty?
|
147
|
+
|
135
148
|
point = feature.centroid
|
136
149
|
[point.y, point.x]
|
137
150
|
end
|
@@ -139,16 +152,23 @@ module Charta
|
|
139
152
|
# Returns a POINT guaranteed to lie on the surface.
|
140
153
|
def point_on_surface
|
141
154
|
return nil unless surface?
|
155
|
+
|
142
156
|
point = feature.point_on_surface
|
143
157
|
[point.y, point.x]
|
144
158
|
end
|
145
159
|
|
146
160
|
def convert_to(new_type)
|
147
161
|
case new_type
|
148
|
-
when type
|
149
|
-
|
150
|
-
when :
|
151
|
-
|
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
|
152
172
|
end
|
153
173
|
end
|
154
174
|
|
@@ -176,10 +196,12 @@ module Charta
|
|
176
196
|
def transform(new_srid)
|
177
197
|
return self if new_srid == srid
|
178
198
|
raise 'Proj is not supported. Cannot tranform' unless RGeo::CoordSys::Proj4.supported?
|
199
|
+
|
179
200
|
new_srid = Charta::SRS[new_srid] || new_srid
|
180
201
|
database = self.class.srs_database
|
181
202
|
new_proj_entry = database.get(new_srid)
|
182
203
|
raise "Cannot find proj for SRID: #{new_srid}" if new_proj_entry.nil?
|
204
|
+
|
183
205
|
new_feature = RGeo::CoordSys::Proj4.transform(
|
184
206
|
database.get(srid).proj4,
|
185
207
|
feature,
|
@@ -199,6 +221,7 @@ module Charta
|
|
199
221
|
other_geometry = Charta.new_geometry(other).transform(srid)
|
200
222
|
feature.union(other_geometry.feature)
|
201
223
|
end
|
224
|
+
|
202
225
|
alias + merge
|
203
226
|
|
204
227
|
def intersection(other)
|
@@ -206,10 +229,16 @@ module Charta
|
|
206
229
|
feature.intersection(other_geometry.feature)
|
207
230
|
end
|
208
231
|
|
232
|
+
def intersects?(other)
|
233
|
+
other_geometry = Charta.new_geometry(other).transform(srid)
|
234
|
+
feature.intersects?(other_geometry.feature)
|
235
|
+
end
|
236
|
+
|
209
237
|
def difference(other)
|
210
238
|
other_geometry = Charta.new_geometry(other).transform(srid)
|
211
239
|
feature.difference(other_geometry.feature)
|
212
240
|
end
|
241
|
+
|
213
242
|
alias - difference
|
214
243
|
|
215
244
|
def bounding_box
|
@@ -234,22 +263,24 @@ module Charta
|
|
234
263
|
Charta.find_srid(name_or_srid)
|
235
264
|
end
|
236
265
|
|
237
|
-
#
|
238
|
-
# serialization in time.
|
266
|
+
# Returns the underlaying object managed by Charta: the RGeo feature
|
239
267
|
def feature
|
240
268
|
unless defined? @feature
|
241
269
|
if defined? @ewkt
|
242
270
|
@feature = ::Charta::Geometry.from_ewkt(@ewkt)
|
243
271
|
@properties = @options.dup if @options
|
244
272
|
else
|
245
|
-
raise StandardError
|
273
|
+
raise StandardError.new('Invalid geometry (no feature, no EWKT)')
|
246
274
|
end
|
247
275
|
end
|
248
276
|
@feature.dup
|
249
277
|
end
|
250
278
|
|
279
|
+
alias to_rgeo feature
|
280
|
+
|
251
281
|
def feature=(new_feature)
|
252
|
-
raise ArgumentError
|
282
|
+
raise ArgumentError.new("Feature can't be nil") if new_feature.nil?
|
283
|
+
|
253
284
|
@feature = new_feature
|
254
285
|
end
|
255
286
|
|
@@ -257,6 +288,21 @@ module Charta
|
|
257
288
|
{ type: 'Feature', properties: properties, geometry: to_json_object }
|
258
289
|
end
|
259
290
|
|
291
|
+
def method_missing(name, *args, &block)
|
292
|
+
target = to_rgeo
|
293
|
+
if target.respond_to? name
|
294
|
+
target.send name, *args
|
295
|
+
else
|
296
|
+
raise StandardError.new("Method #{name} does not exist for #{self.class.name}")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def respond_to_missing?(name, include_private = false)
|
301
|
+
return false if name == :init_with
|
302
|
+
|
303
|
+
super
|
304
|
+
end
|
305
|
+
|
260
306
|
class << self
|
261
307
|
def srs_database
|
262
308
|
@srs_database ||= RGeo::CoordSys::SRSDatabase::Proj4Data.new('epsg', authority: 'EPSG', cache: true)
|
@@ -264,11 +310,13 @@ module Charta
|
|
264
310
|
|
265
311
|
def factory(srid = 4326)
|
266
312
|
return projected_factory(srid) if srid.to_i == 4326
|
313
|
+
|
267
314
|
geos_factory(srid)
|
268
315
|
end
|
269
316
|
|
270
317
|
def feature(ewkt_or_rgeo)
|
271
318
|
return from_rgeo(ewkt_or_rgeo) if ewkt_or_rgeo.is_a? RGeo::Feature::Instance
|
319
|
+
|
272
320
|
from_ewkt(ewkt_or_rgeo)
|
273
321
|
end
|
274
322
|
|
@@ -279,7 +327,7 @@ module Charta
|
|
279
327
|
|
280
328
|
def from_ewkt(ewkt)
|
281
329
|
# Cleans empty geometries
|
282
|
-
ewkt.gsub
|
330
|
+
ewkt = ewkt.gsub(/(GEOMETRYCOLLECTION|GEOMETRY|((MULTI)?(POINT|LINESTRING|POLYGON)))\(\)/, '\1 EMPTY')
|
283
331
|
srs = ewkt.split(/[\=\;]+/)[0..1]
|
284
332
|
srid = nil
|
285
333
|
srid = srs[1] if srs[0] =~ /srid/i
|
@@ -291,57 +339,52 @@ module Charta
|
|
291
339
|
|
292
340
|
private
|
293
341
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
def projected_factory(srid)
|
317
|
-
proj4 = '+proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'
|
318
|
-
RGeo::Geographic.projected_factory(
|
319
|
-
srid: srid,
|
320
|
-
wkt_generator: {
|
321
|
-
type_format: :ewkt,
|
322
|
-
emit_ewkt_srid: true,
|
323
|
-
convert_case: :upper
|
324
|
-
},
|
325
|
-
wkt_parser: {
|
326
|
-
support_ewkt: true
|
327
|
-
},
|
328
|
-
wkb_generator: {
|
329
|
-
type_format: :ewkb,
|
330
|
-
emit_ewkb_srid: true,
|
331
|
-
hex_format: true
|
332
|
-
},
|
333
|
-
wkb_parser: {
|
334
|
-
support_ewkb: true
|
335
|
-
},
|
336
|
-
projection_srid: 6933,
|
337
|
-
projection_proj4: proj4
|
338
|
-
)
|
339
|
-
end
|
340
|
-
end
|
342
|
+
def geos_factory(srid)
|
343
|
+
RGeo::Geos.factory(
|
344
|
+
srid: srid,
|
345
|
+
wkt_generator: {
|
346
|
+
type_format: :ewkt,
|
347
|
+
emit_ewkt_srid: true,
|
348
|
+
convert_case: :upper
|
349
|
+
},
|
350
|
+
wkt_parser: {
|
351
|
+
support_ewkt: true
|
352
|
+
},
|
353
|
+
wkb_generator: {
|
354
|
+
type_format: :ewkb,
|
355
|
+
emit_ewkb_srid: true,
|
356
|
+
hex_format: true
|
357
|
+
},
|
358
|
+
wkb_parser: {
|
359
|
+
support_ewkb: true
|
360
|
+
}
|
361
|
+
)
|
362
|
+
end
|
341
363
|
|
342
|
-
|
343
|
-
|
344
|
-
|
364
|
+
def projected_factory(srid)
|
365
|
+
proj4 = '+proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'
|
366
|
+
RGeo::Geographic.projected_factory(
|
367
|
+
srid: srid,
|
368
|
+
wkt_generator: {
|
369
|
+
type_format: :ewkt,
|
370
|
+
emit_ewkt_srid: true,
|
371
|
+
convert_case: :upper
|
372
|
+
},
|
373
|
+
wkt_parser: {
|
374
|
+
support_ewkt: true
|
375
|
+
},
|
376
|
+
wkb_generator: {
|
377
|
+
type_format: :ewkb,
|
378
|
+
emit_ewkb_srid: true,
|
379
|
+
hex_format: true
|
380
|
+
},
|
381
|
+
wkb_parser: {
|
382
|
+
support_ewkb: true
|
383
|
+
},
|
384
|
+
projection_srid: 6933,
|
385
|
+
projection_proj4: proj4
|
386
|
+
)
|
387
|
+
end
|
345
388
|
end
|
346
389
|
end
|
347
390
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Charta
|
2
2
|
# Represent a Geometry with contains other geometries
|
3
3
|
class GeometryCollection < Geometry
|
4
|
-
|
5
|
-
srid =
|
6
|
-
|
7
|
-
|
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
|
-
|
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 =
|
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
|
data/lib/charta/gml_import.rb
CHANGED
@@ -63,30 +63,30 @@ class GmlImport
|
|
63
63
|
|
64
64
|
private
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|