charta 0.2.3 → 0.3.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.
- checksums.yaml +4 -4
- data/charta.gemspec +20 -20
- data/lib/charta.rb +36 -89
- data/lib/charta/coordinates.rb +17 -17
- data/lib/charta/ewkt_serializer.rb +10 -1
- 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 +4 -1
- data/lib/charta/geometry.rb +22 -12
- 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 +2 -1
- data/lib/charta/version.rb +1 -1
- data/lib/rgeo/svg.rb +44 -44
- metadata +65 -46
- data/.gitignore +0 -13
- data/.gitlab-ci.yml +0 -14
- 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
@@ -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
|
data/lib/charta/geo_json.rb
CHANGED
@@ -48,7 +48,10 @@ module Charta
|
|
48
48
|
Coordinates.flatten hash
|
49
49
|
end
|
50
50
|
|
51
|
-
%i[
|
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
|
data/lib/charta/geometry.rb
CHANGED
@@ -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
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
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
|
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
|
-
|
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
|