rgeo-kml 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Version +1 -0
- data/lib/rgeo-kml.rb +7 -0
- data/lib/rgeo/kml.rb +39 -0
- data/lib/rgeo/kml/coder.rb +222 -0
- data/lib/rgeo/kml/coordinates_builder.rb +37 -0
- data/lib/rgeo/kml/entities.rb +275 -0
- data/lib/rgeo/kml/interface.rb +99 -0
- data/lib/rgeo/kml/kml_stream_listener.rb +82 -0
- data/lib/rgeo/kml/line_string_builder.rb +20 -0
- data/lib/rgeo/kml/linear_ring_builder.rb +20 -0
- data/lib/rgeo/kml/multi_geometry_builder.rb +73 -0
- data/lib/rgeo/kml/point_builder.rb +20 -0
- data/lib/rgeo/kml/polygon_builder.rb +26 -0
- data/lib/rgeo/kml/version.rb +26 -0
- data/test/tc_basic_test.rb +328 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 06227b992bdd5a2c5169650431585db1648c8b04
|
4
|
+
data.tar.gz: df4e6c62b71585076ddafef8721e85f770b4f871
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4fb3bb15dd469492f7dda89d9a6141441531e9afa19f3166ba40d253a690ad1b56df2fb212d11276cf3a7979bd1fce0831653bd9f16d42ae1225e0e3a4804c3d
|
7
|
+
data.tar.gz: 786a6e34ea432784590336be029e4e466ea47ad8d3644701ce2693155953edfcd2a1afb4daf6581525ec9f4577d70fe097230377db22f71fb2f26b6e0533bfba
|
data/Version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/rgeo-kml.rb
ADDED
data/lib/rgeo/kml.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Kml implementation for RGeo
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Dependencies
|
8
|
+
require 'rgeo'
|
9
|
+
|
10
|
+
# RGeo is a spatial data library for Ruby, provided by the "rgeo" gem.
|
11
|
+
#
|
12
|
+
# The optional RGeo::GeoJSON module provides a set of tools for GeoJSON
|
13
|
+
# encoding and decoding.
|
14
|
+
|
15
|
+
module RGeo
|
16
|
+
|
17
|
+
|
18
|
+
# This is a namespace for a set of tools that provide KML encoding.
|
19
|
+
# See https://developers.google.com/kml/documentation/ for more information about this specification.
|
20
|
+
|
21
|
+
module Kml
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Implementation files
|
29
|
+
require 'rgeo/kml/version'
|
30
|
+
require 'rgeo/kml/entities'
|
31
|
+
require 'rgeo/kml/coder'
|
32
|
+
require 'rgeo/kml/interface'
|
33
|
+
require 'rgeo/kml/kml_stream_listener'
|
34
|
+
require 'rgeo/kml/coordinates_builder'
|
35
|
+
require 'rgeo/kml/point_builder'
|
36
|
+
require 'rgeo/kml/line_string_builder'
|
37
|
+
require 'rgeo/kml/linear_ring_builder'
|
38
|
+
require 'rgeo/kml/polygon_builder'
|
39
|
+
require 'rgeo/kml/multi_geometry_builder'
|
@@ -0,0 +1,222 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Kml encoder object
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
|
7
|
+
require "rexml/document"
|
8
|
+
require 'rexml/parsers/pullparser'
|
9
|
+
|
10
|
+
module RGeo
|
11
|
+
|
12
|
+
module Kml
|
13
|
+
|
14
|
+
|
15
|
+
# This object encapsulates encoding and decoding settings (principally
|
16
|
+
# the RGeo::Feature::Factory and the RGeo::Kml::EntityFactory to
|
17
|
+
# be used) so that you can encode and decode without specifying those
|
18
|
+
# settings every time.
|
19
|
+
|
20
|
+
class Coder
|
21
|
+
|
22
|
+
ELEMENT_MAP = {
|
23
|
+
'Point' => "point",
|
24
|
+
'LineString' => "line_string",
|
25
|
+
'LinearRing' => "linear_ring",
|
26
|
+
'Polygon' => "polygon",
|
27
|
+
'MultiGeometry' => "geometry_collection"
|
28
|
+
}
|
29
|
+
|
30
|
+
@@kml_available = nil
|
31
|
+
@@activesupport_available = nil
|
32
|
+
|
33
|
+
|
34
|
+
# Create a new coder settings object. The geo factory is passed as
|
35
|
+
# a required argument.
|
36
|
+
#
|
37
|
+
# Options include:
|
38
|
+
#
|
39
|
+
# [<tt>:geo_factory</tt>]
|
40
|
+
# Specifies the geo factory to use to create geometry objects.
|
41
|
+
# Defaults to the preferred cartesian factory.
|
42
|
+
# [<tt>:entity_factory</tt>]
|
43
|
+
# Specifies an entity factory, which lets you override the types
|
44
|
+
# of Kml entities that are created. It defaults to the default
|
45
|
+
# RGeo::Kml::EntityFactory, which generates objects of type
|
46
|
+
# RGeo::Kml::Feature or RGeo::Kml::FeatureCollection.
|
47
|
+
# See RGeo::Kml::EntityFactory for more information.
|
48
|
+
|
49
|
+
def initialize(opts_={})
|
50
|
+
@geo_factory = opts_[:geo_factory] || ::RGeo::Cartesian.preferred_factory
|
51
|
+
@entity_factory = opts_[:entity_factory] || EntityFactory.instance
|
52
|
+
@buffer = ''
|
53
|
+
|
54
|
+
@num_coordinates = 2
|
55
|
+
@num_coordinates += 1 if @geo_factory.property(:has_z_coordinate)
|
56
|
+
@num_coordinates += 1 if @geo_factory.property(:has_m_coordinate)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Encode the given object as Kml. The object may be one of the
|
61
|
+
# geometry objects specified in RGeo::Feature, or an appropriate
|
62
|
+
# Kml wrapper entity supported by this coder's entity factory.
|
63
|
+
#
|
64
|
+
# This method returns a KML object (xml with Placemark).
|
65
|
+
#
|
66
|
+
# Returns nil if nil is passed in as the object.
|
67
|
+
|
68
|
+
def encode(object_)
|
69
|
+
if @entity_factory.is_feature_collection?(object_)
|
70
|
+
{
|
71
|
+
'type' => 'FeatureCollection',
|
72
|
+
'features' => @entity_factory.map_feature_collection(object_){ |f_| _encode_feature(f_) },
|
73
|
+
}
|
74
|
+
elsif @entity_factory.is_feature?(object_)
|
75
|
+
_encode_feature(object_)
|
76
|
+
elsif object_.nil?
|
77
|
+
nil
|
78
|
+
else
|
79
|
+
_encode_geometry(object_)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# Returns the RGeo::Feature::Factory used to generate geometry objects.
|
85
|
+
|
86
|
+
def geo_factory
|
87
|
+
@geo_factory
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# Returns the RGeo::Kml::EntityFactory used to generate Kml
|
92
|
+
# wrapper entities.
|
93
|
+
|
94
|
+
def entity_factory
|
95
|
+
@entity_factory
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def _encode_feature(object_) # :nodoc:
|
100
|
+
id_ = @entity_factory.get_feature_id(object_)
|
101
|
+
kml_ = '<?xml version="1.0" encoding="UTF-8"?>\n'
|
102
|
+
kml_ += '<kml xmlns="http://www.opengis.net/kml/2.2">\n'
|
103
|
+
kml_ += "<Document>"
|
104
|
+
kml_ += "<name>Kml File</name>"
|
105
|
+
kml_ += "<Placemark id="#{id_}">\n"
|
106
|
+
kml_ += _encode_geometry(@entity_factory.get_feature_geometry(object_))
|
107
|
+
kml_ += "</Placemark>\n"
|
108
|
+
kml_ += "</Document>"
|
109
|
+
kml_ += "</kml>"
|
110
|
+
|
111
|
+
# 'properties' => @entity_factory.get_feature_properties(object_).dup,
|
112
|
+
# id_ = @entity_factory.get_feature_id(object_)
|
113
|
+
# json_['id'] = id_ if id_
|
114
|
+
kml_
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def _encode_geometry(object_, point_encoder_=nil) # :nodoc:
|
119
|
+
unless point_encoder_
|
120
|
+
if object_.factory.property(:has_z_coordinate)
|
121
|
+
if object_.factory.property(:has_m_coordinate)
|
122
|
+
point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.z, p_.m].join(",") }
|
123
|
+
else
|
124
|
+
point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.z].join(",") }
|
125
|
+
end
|
126
|
+
else
|
127
|
+
if object_.factory.property(:has_m_coordinate)
|
128
|
+
point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y, p_.m].join(",") }
|
129
|
+
else
|
130
|
+
point_encoder_ = ::Proc.new{ |p_| [p_.x, p_.y].join(",") }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
case object_
|
135
|
+
when ::RGeo::Feature::Point
|
136
|
+
result = "<Point>\n"
|
137
|
+
#result += options[:geom_data] if options[:geom_data]
|
138
|
+
result += "<coordinates>" + point_encoder_.call(object_)
|
139
|
+
result += "</coordinates>\n"
|
140
|
+
result += "</Point>\n"
|
141
|
+
when ::RGeo::Feature::LineString
|
142
|
+
result = "<LineString>\n"
|
143
|
+
#result += options[:geom_data] if options[:geom_data]
|
144
|
+
result += "<coordinates>\n"
|
145
|
+
result += object_.points.map(&point_encoder_).join("\n")
|
146
|
+
result += "\n</coordinates>\n"
|
147
|
+
result += "</LineString>\n"
|
148
|
+
when ::RGeo::Feature::Polygon
|
149
|
+
result = "<Polygon>\n"
|
150
|
+
#result += options[:geom_data] if options[:geom_data]
|
151
|
+
result += "<outerBoundaryIs><LinearRing><coordinates>\n"
|
152
|
+
result += object_.exterior_ring.points.map(&point_encoder_).join("\n")
|
153
|
+
result += "\n</coordinates></LinearRing></outerBoundaryIs>\n"
|
154
|
+
object_.interior_rings.each do |interior_ring|
|
155
|
+
result += "<innerBoundaryIs><LinearRing><coordinates>\n"
|
156
|
+
result += interior_ring.points.map(&point_encoder_).join("\n")
|
157
|
+
result += "\n</coordinates></LinearRing></innerBoundaryIs>\n"
|
158
|
+
end
|
159
|
+
result += "</Polygon>\n"
|
160
|
+
when ::RGeo::Feature::MultiPoint
|
161
|
+
result = "<MultiGeometry>\n"
|
162
|
+
object_.each do |geometry|
|
163
|
+
result += "<Point>\n<coordinates>"
|
164
|
+
#options[:id_attr] = "" #the subgeometries do not have an ID
|
165
|
+
result += point_encoder_.call(geometry)
|
166
|
+
result += "</coordinates>\n</Point>\n"
|
167
|
+
end
|
168
|
+
result += "</MultiGeometry>\n"
|
169
|
+
when ::RGeo::Feature::MultiLineString
|
170
|
+
result = "<MultiGeometry>\n"
|
171
|
+
object_.each do |geometry|
|
172
|
+
#options[:id_attr] = "" #the subgeometries do not have an ID
|
173
|
+
result += "<LineString>\n"
|
174
|
+
#result += options[:geom_data] if options[:geom_data]
|
175
|
+
result += "<coordinates>\n"
|
176
|
+
result += geometry.points.map(&point_encoder_).join("\n")
|
177
|
+
result += "\n</coordinates>\n"
|
178
|
+
result += "</LineString>\n"
|
179
|
+
end
|
180
|
+
result += "</MultiGeometry>\n"
|
181
|
+
when ::RGeo::Feature::MultiPolygon
|
182
|
+
result = "<MultiGeometry>\n"
|
183
|
+
object_.each do |geometry|
|
184
|
+
#options[:id_attr] = "" #the subgeometries do not have an ID
|
185
|
+
result += "<Polygon>\n"
|
186
|
+
#result += options[:geom_data] if options[:geom_data]
|
187
|
+
result += "<outerBoundaryIs><LinearRing><coordinates>\n"
|
188
|
+
result += geometry.exterior_ring.points.map(&point_encoder_).join("\n")
|
189
|
+
result += "\n</coordinates></LinearRing></outerBoundaryIs>\n"
|
190
|
+
geometry.interior_rings.each do |interior_ring|
|
191
|
+
result += "<innerBoundaryIs><LinearRing><coordinates>\n"
|
192
|
+
result += interior_ring.points.map(&point_encoder_).join("\n")
|
193
|
+
result += "\n</coordinates></LinearRing></innerBoundaryIs>\n"
|
194
|
+
end
|
195
|
+
result += "</Polygon>\n"
|
196
|
+
end
|
197
|
+
result += "</MultiGeometry>\n"
|
198
|
+
when ::RGeo::Feature::GeometryCollection
|
199
|
+
result = "<MultiGeometry>\n"
|
200
|
+
#options[:id_attr] = "" #the subgeometries do not have an ID
|
201
|
+
result += object_.map{ |geom_| _encode_geometry(geom_, point_encoder_) }.join("")
|
202
|
+
result += "</MultiGeometry>\n"
|
203
|
+
else
|
204
|
+
nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
# Decode an object from Kml. The input may a
|
210
|
+
# String, or an IO object from which to read the KML string.
|
211
|
+
# If an error occurs, nil is returned.
|
212
|
+
def decode(input_)
|
213
|
+
@kml_stream_listener = KmlStreamListener.new(geo_factory)
|
214
|
+
@kml_stream_listener.parse(input_)
|
215
|
+
@kml_stream_listener.result
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RGeo
|
2
|
+
module Kml
|
3
|
+
|
4
|
+
class CoordinatesBuilder
|
5
|
+
attr_reader :geo_factory, :parent, :points
|
6
|
+
attr_accessor :text
|
7
|
+
|
8
|
+
def initialize( geo_factory, parent)
|
9
|
+
@geo_factory = geo_factory
|
10
|
+
@parent = parent
|
11
|
+
@points = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def build
|
15
|
+
@text.gsub(/\n/, ' ').strip.split(/\s+/).each do |coord|
|
16
|
+
x, y, z = coord.split(',')
|
17
|
+
if x.nil? || y.nil?
|
18
|
+
fail StandardError, 'Coordinates must have at least x and y elements'
|
19
|
+
end
|
20
|
+
if z.nil?
|
21
|
+
@points << @geo_factory.point(x, y)
|
22
|
+
else
|
23
|
+
@points << @geo_factory.point(x, y, z)
|
24
|
+
end
|
25
|
+
|
26
|
+
@points
|
27
|
+
end
|
28
|
+
|
29
|
+
rescue Exception => e
|
30
|
+
puts "Exception #{e.message} \n #{e.backtrace}"
|
31
|
+
raise StandardError, 'Error parsing coordinates: check your kml for errors'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Kml standard entities
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
|
7
|
+
|
8
|
+
module RGeo
|
9
|
+
|
10
|
+
module Kml
|
11
|
+
|
12
|
+
|
13
|
+
# This is a Kml wrapper entity that corresponds to the Kml
|
14
|
+
# "Feature" type. It is an immutable type.
|
15
|
+
#
|
16
|
+
# This is the default implementation that is generated by
|
17
|
+
# RGeo::Kml::EntityFactory. You may replace this implementation
|
18
|
+
# by writing your own entity factory. Note that an alternate Feature
|
19
|
+
# implementation need not subclass or even duck-type this class.
|
20
|
+
# the entity factory mediates all interaction between the Kml
|
21
|
+
# engine and features.
|
22
|
+
|
23
|
+
class Feature
|
24
|
+
|
25
|
+
|
26
|
+
# Create a feature wrapping the given geometry, with the given ID
|
27
|
+
# and properties.
|
28
|
+
|
29
|
+
def initialize(geometry_, id_=nil, properties_={})
|
30
|
+
@geometry = geometry_
|
31
|
+
@id = id_
|
32
|
+
@properties = {}
|
33
|
+
properties_.each do |k_, v_|
|
34
|
+
@properties[k_.to_s] = v_
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def inspect # :nodoc:
|
40
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} id=#{@id.inspect} geom=#{@geometry ? @geometry.as_text.inspect : 'nil'}>"
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s # :nodoc:
|
44
|
+
inspect
|
45
|
+
end
|
46
|
+
|
47
|
+
def hash # :nodoc:
|
48
|
+
@geometry.hash + @id.hash + @properties.hash
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Two features are equal if their geometries, IDs, and properties
|
53
|
+
# are all equal.
|
54
|
+
# This method uses the eql? method to test geometry equality, which
|
55
|
+
# may behave differently than the == operator.
|
56
|
+
|
57
|
+
def eql?(rhs_)
|
58
|
+
rhs_.kind_of?(Feature) && @geometry.eql?(rhs_.geometry) && @id.eql?(rhs_.feature_id) && @properties.eql?(rhs_.instance_variable_get(:@properties))
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Two features are equal if their geometries, IDs, and properties
|
63
|
+
# are all equal.
|
64
|
+
# This method uses the == operator to test geometry equality, which
|
65
|
+
# may behave differently than the eql? method.
|
66
|
+
|
67
|
+
def ==(rhs_)
|
68
|
+
rhs_.kind_of?(Feature) && @geometry == rhs_.geometry && @id == rhs_.feature_id && @properties == rhs_.instance_variable_get(:@properties)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Returns the geometry contained in this feature, which may be nil.
|
73
|
+
|
74
|
+
def geometry
|
75
|
+
@geometry
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Returns the ID for this feature, which may be nil.
|
80
|
+
|
81
|
+
def feature_id
|
82
|
+
@id
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Returns a copy of the properties for this feature.
|
87
|
+
|
88
|
+
def properties
|
89
|
+
@properties.dup
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
# Gets the value of the given named property.
|
94
|
+
# Returns nil if the given property is not found.
|
95
|
+
|
96
|
+
def property(key_)
|
97
|
+
@properties[key_.to_s]
|
98
|
+
end
|
99
|
+
alias_method :[], :property
|
100
|
+
|
101
|
+
|
102
|
+
# Gets an array of the known property keys in this feature.
|
103
|
+
|
104
|
+
def keys
|
105
|
+
@properties.keys
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# This is a Kml wrapper entity that corresponds to the Kml
|
113
|
+
# "FeatureCollection" type. It is an immutable type.
|
114
|
+
#
|
115
|
+
# This is the default implementation that is generated by
|
116
|
+
# RGeo::Kml::EntityFactory. You may replace this implementation
|
117
|
+
# by writing your own entity factory. Note that an alternate
|
118
|
+
# FeatureCollection implementation need not subclass or even
|
119
|
+
# duck-type this class. The entity factory mediates all interaction
|
120
|
+
# between the Kml engine and feature collections.
|
121
|
+
|
122
|
+
class FeatureCollection
|
123
|
+
|
124
|
+
include ::Enumerable
|
125
|
+
|
126
|
+
|
127
|
+
# Create a new FeatureCollection with the given features, which must
|
128
|
+
# be provided as an Enumerable.
|
129
|
+
|
130
|
+
def initialize(features_=[])
|
131
|
+
@features = []
|
132
|
+
features_.each{ |f_| @features << f_ if f_.kind_of?(Feature) }
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def inspect # :nodoc:
|
137
|
+
"#<#{self.class}:0x#{object_id.to_s(16)}>"
|
138
|
+
end
|
139
|
+
|
140
|
+
def to_s # :nodoc:
|
141
|
+
inspect
|
142
|
+
end
|
143
|
+
|
144
|
+
def hash # :nodoc:
|
145
|
+
@features.hash
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# Two feature collections are equal if they contain the same
|
150
|
+
# features in the same order.
|
151
|
+
# This methods uses the eql? method to test geometry equality, which
|
152
|
+
# may behave differently than the == operator.
|
153
|
+
|
154
|
+
def eql?(rhs_)
|
155
|
+
rhs_.kind_of?(FeatureCollection) && @features.eql?(rhs_.instance_variable_get(:@features))
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# Two feature collections are equal if they contain the same
|
160
|
+
# features in the same order.
|
161
|
+
# This methods uses the == operator to test geometry equality, which
|
162
|
+
# may behave differently than the eql? method.
|
163
|
+
|
164
|
+
def ==(rhs_)
|
165
|
+
rhs_.kind_of?(FeatureCollection) && @features == rhs_.instance_variable_get(:@features)
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
# Iterates or returns an iterator for the features.
|
170
|
+
|
171
|
+
def each(&block_)
|
172
|
+
@features.each(&block_)
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
# Returns the number of features contained in this collection.
|
177
|
+
|
178
|
+
def size
|
179
|
+
@features.size
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
# Access a feature by index.
|
184
|
+
|
185
|
+
def [](index_)
|
186
|
+
@features[index_]
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
# This is the default entity factory. It creates objects of type
|
194
|
+
# RGeo::Kml::Feature and RGeo::Kml::FeatureCollection.
|
195
|
+
# You may create your own entity factory by duck-typing this class.
|
196
|
+
|
197
|
+
class EntityFactory
|
198
|
+
|
199
|
+
|
200
|
+
# Create and return a new feature, given geometry, ID, and
|
201
|
+
# properties hash. Note that, per the Kml spec, geometry and/or
|
202
|
+
# properties may be nil.
|
203
|
+
|
204
|
+
def feature(geometry_, id_=nil, properties_=nil)
|
205
|
+
Feature.new(geometry_, id_, properties_ || {})
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
# Create and return a new feature collection, given an enumerable
|
210
|
+
# of feature objects.
|
211
|
+
|
212
|
+
def feature_collection(features_=[])
|
213
|
+
FeatureCollection.new(features_)
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
# Returns true if the given object is a feature created by this
|
218
|
+
# entity factory.
|
219
|
+
|
220
|
+
def is_feature?(object_)
|
221
|
+
object_.kind_of?(Feature)
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
# Returns true if the given object is a feature collection created
|
226
|
+
# by this entity factory.
|
227
|
+
|
228
|
+
def is_feature_collection?(object_)
|
229
|
+
object_.kind_of?(FeatureCollection)
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
# Run Enumerable#map on the features contained in the given feature
|
234
|
+
# collection.
|
235
|
+
|
236
|
+
def map_feature_collection(object_, &block_)
|
237
|
+
object_.map(&block_)
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
# Returns the geometry associated with the given feature.
|
242
|
+
|
243
|
+
def get_feature_geometry(object_)
|
244
|
+
object_.geometry
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
# Returns the ID of the given feature, or nil for no ID.
|
249
|
+
|
250
|
+
def get_feature_id(object_)
|
251
|
+
object_.feature_id
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
# Returns the properties of the given feature as a hash. Editing
|
256
|
+
# this hash does not change the state of the feature.
|
257
|
+
|
258
|
+
def get_feature_properties(object_)
|
259
|
+
object_.properties
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
# Return the singleton instance of EntityFactory.
|
264
|
+
|
265
|
+
def self.instance
|
266
|
+
@instance ||= self.new
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|