kamelopard 0.0.3 → 0.0.4

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.
@@ -4,1703 +4,1862 @@
4
4
  # http://code.google.com/apis/kml/documentation/kmlreference.html for a
5
5
  # description of KML
6
6
 
7
- require 'singleton'
8
- require 'kamelopard/pointlist'
9
-
10
- @@sequence = 0
11
-
12
- def get_next_id # :nodoc
13
- @@sequence += 1
14
- @@sequence
15
- end
16
-
17
- #--
18
- # Print out a set of kml fields. Expects an array argument. Each entry in the
19
- # array is itself an array, containing two strings and a boolean. If the first
20
- # string is nil, the function won't print anything for that element. If it's
21
- # not null, it consults the boolean. True values tell the function to treat the
22
- # second string as a KML element name, and print it along with XML decorators
23
- # and the field value. False values mean just print the second string, with no
24
- # decorators and no other values
25
- #++
26
- def kml_array(m, indent = 0) # :nodoc
27
- k = ''
28
- m.map do |a|
29
- r = ''
30
- if ! a[0].nil? then
31
- if a[2] then
32
- r << "#{ ' ' * indent}<" << a[1] << '>' << a[0].to_s << '</' << a[1] << ">\n"
33
- else
34
- r << a[1] << "\n"
7
+ module Kamelopard
8
+ require 'singleton'
9
+ require 'kamelopard/pointlist'
10
+ require 'rexml/document'
11
+ require 'rexml/element'
12
+
13
+ @@sequence = 0
14
+
15
+ def Kamelopard.get_document
16
+ Document.instance
17
+ end
18
+
19
+ def Kamelopard.get_next_id # :nodoc
20
+ @@sequence += 1
21
+ @@sequence
22
+ end
23
+
24
+ #--
25
+ # Intelligently adds elements to a KML object. Expects the KML object as the
26
+ # first argument, an array as the second. Each entry in the array is itself an
27
+ # array, containing first an Object, and second either a string or a Proc
28
+ # object. If the first Object is nil, nothing happens. If it's not nil, then:
29
+ # * if the second element is a string, add a new element to the KML. This
30
+ # string is the element name, and the stringified form of the first element
31
+ # is its text value
32
+ # * if the second element is a proc, call the proc, passing it the KML
33
+ # object, and let the Proc (presumably) add itself to the KML
34
+ #++
35
+ def Kamelopard.kml_array(e, m) # :nodoc
36
+ m.map do |a|
37
+ if ! a[0].nil? then
38
+ if a[1].kind_of? Proc then
39
+ a[1].call(e)
40
+ else
41
+ t = REXML::Element.new a[1]
42
+ t.text = a[0].to_s
43
+ e.elements.add t
44
+ end
35
45
  end
36
46
  end
37
- k << r
38
47
  end
39
- k
40
- end
41
48
 
42
- #--
43
- # Accepts XdX'X.X", XDXmX.XXs, XdXmX.XXs, or X.XXXX with either +/- or N/E/S/W
44
- #++
45
- def convert_coord(a) # :nodoc
46
- a = a.to_s.upcase.strip
49
+ #--
50
+ # Accepts XdX'X.X", XDXmX.XXs, XdXmX.XXs, or X.XXXX with either +/- or N/E/S/W
51
+ #++
52
+ def Kamelopard.convert_coord(a) # :nodoc
53
+ a = a.to_s.upcase.strip
47
54
 
48
- mult = 1
49
- if a =~ /^-/ then
50
- mult *= -1
51
- end
52
- a = a.sub /^\+|-/, ''
53
- a = a.strip
54
-
55
- if a =~ /[SW]$/ then
56
- mult *= -1
57
- end
58
- a = a.sub /[NESW]$/, ''
59
- a = a.strip
60
-
61
- if a =~ /^\d+(\.\d+)?$/ then
62
- # coord needs no transformation
63
- 1
64
- elsif a =~ /^\d+D\d+M\d+(\.\d+)?S$/ then
65
- # coord is in dms
66
- p = a.split /[D"']/
67
- a = p[0].to_f + (p[2].to_f / 60.0 + p[1].to_f) / 60.0
68
- elsif a =~ /^\d+D\d+'\d+(\.\d+)?"$/ then
69
- # coord is in d'"
70
- p = a.split /[D"']/
71
- a = p[0].to_f + (p[2].to_f / 60.0 + p[1].to_f) / 60.0
72
- else
73
- raise "Couldn't determine coordinate format for #{a}"
74
- end
75
-
76
- # check that it's within range
77
- a = a.to_f * mult
78
- raise "Coordinate #{a} out of range" if a > 180 or a < -180
79
- return a
80
- end
55
+ mult = 1
56
+ if a =~ /^-/ then
57
+ mult *= -1
58
+ end
59
+ a = a.sub /^\+|-/, ''
60
+ a = a.strip
81
61
 
82
- # Base class for all Kamelopard objects. Manages object ID and a single
83
- # comment string associated with the object
84
- class KMLObject
85
- attr_accessor :id, :comment
62
+ if a =~ /[SW]$/ then
63
+ mult *= -1
64
+ end
65
+ a = a.sub /[NESW]$/, ''
66
+ a = a.strip
67
+
68
+ if a =~ /^\d+(\.\d+)?$/ then
69
+ # coord needs no transformation
70
+ 1
71
+ elsif a =~ /^\d+D\d+M\d+(\.\d+)?S$/ then
72
+ # coord is in dms
73
+ p = a.split /[D"']/
74
+ a = p[0].to_f + (p[2].to_f / 60.0 + p[1].to_f) / 60.0
75
+ elsif a =~ /^\d+D\d+'\d+(\.\d+)?"$/ then
76
+ # coord is in d'"
77
+ p = a.split /[D"']/
78
+ a = p[0].to_f + (p[2].to_f / 60.0 + p[1].to_f) / 60.0
79
+ else
80
+ raise "Couldn't determine coordinate format for #{a}"
81
+ end
86
82
 
87
- def initialize(comment = nil)
88
- @id = "#{self.class.name}_#{ get_next_id }"
89
- @comment = comment.gsub(/</, '&lt;') unless comment.nil?
83
+ # check that it's within range
84
+ a = a.to_f * mult
85
+ raise "Coordinate #{a} out of range" if a > 180 or a < -180
86
+ return a
90
87
  end
91
88
 
92
- # Returns KML string for this object. Objects should override this method
93
- def to_kml(indent = 0)
94
- if @comment.nil? or @comment == '' then
95
- ''
89
+ # Helper function for altitudeMode / gx:altitudeMode elements
90
+ def Kamelopard.add_altitudeMode(mode, e)
91
+ return if mode.nil?
92
+ if mode == :clampToGround or mode == :relativeToGround or mode == :absolute then
93
+ t = REXML::Element.new 'altitudeMode'
96
94
  else
97
- "#{ ' ' * indent }<!-- #{ @comment } -->\n"
95
+ t = REXML::Element.new 'gx:altitudeMode'
98
96
  end
97
+ t.text = mode
98
+ e.elements.add t
99
99
  end
100
- end
101
100
 
102
- # Abstract base class for KMLPoint and several other classes
103
- class Geometry < KMLObject
104
- end
101
+ # Base class for all Kamelopard objects. Manages object ID and a single
102
+ # comment string associated with the object
103
+ class Object
104
+ attr_accessor :id, :comment
105
105
 
106
- # Represents a Point in KML.
107
- class KMLPoint < Geometry
108
- attr_accessor :longitude, :latitude, :altitude, :altitudeMode, :extrude
109
- def initialize(long, lat, alt=0, altmode=:clampToGround, extrude=false)
110
- super()
111
- @longitude = convert_coord(long)
112
- @latitude = convert_coord(lat)
113
- @altitude = alt
114
- @altitudeMode = altmode
115
- @extrude = extrude
106
+ def initialize(comment = nil)
107
+ @id = "#{self.class.name.gsub('Kamelopard::', '')}_#{ Kamelopard.get_next_id }"
108
+ @comment = comment.gsub(/</, '&lt;') unless comment.nil?
109
+ end
110
+
111
+ # Returns KML string for this object. Objects should override this method
112
+ def to_kml(elem)
113
+ elem.attributes['id'] = @id
114
+ if not @comment.nil? and @comment != '' then
115
+ c = REXML::Comment.new " #{@comment} ", elem
116
+ return c
117
+ end
118
+ end
116
119
  end
117
-
118
- def to_s
119
- "KMLPoint (#{@longitude}, #{@latitude}, #{@altitude}, mode = #{@altitudeMode}, #{ @extrude ? 'extruded' : 'not extruded' })"
120
+
121
+ # Abstract base class for Point and several other classes
122
+ class Geometry < Object
120
123
  end
121
124
 
122
- def to_kml(indent = 0, short = false)
123
- # The short form includes only the coordinates tag
124
- k = super(indent + 4) + "#{ ' ' * indent }<Point id=\"#{ @id }\">\n"
125
- k << "#{ ' ' * indent } <extrude>#{ @extrude ? 1 : 0 }</extrude>\n" unless short
126
- if not short then
127
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
128
- k << "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
129
- else
130
- k << "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
125
+ # Represents a Point in KML.
126
+ class Point < Geometry
127
+ attr_accessor :longitude, :latitude, :altitude, :altitudeMode, :extrude
128
+ def initialize(long, lat, alt=0, altmode=:clampToGround, extrude=false)
129
+ super()
130
+ @longitude = Kamelopard.convert_coord(long)
131
+ @latitude = Kamelopard.convert_coord(lat)
132
+ @altitude = alt
133
+ @altitudeMode = altmode
134
+ @extrude = extrude
135
+ end
136
+
137
+ def to_s
138
+ "Point (#{@longitude}, #{@latitude}, #{@altitude}, mode = #{@altitudeMode}, #{ @extrude ? 'extruded' : 'not extruded' })"
139
+ end
140
+
141
+ def to_kml(short = false)
142
+ e = REXML::Element.new 'Point'
143
+ super(e)
144
+ e.attributes['id'] = @id
145
+ c = REXML::Element.new 'coordinates'
146
+ c.text = "#{ @longitude }, #{ @latitude }, #{ @altitude }"
147
+ e.elements.add c
148
+
149
+ if not short then
150
+ c = REXML::Element.new 'extrude'
151
+ c.text = @extrude ? 1 : 0
152
+ e.elements.add c
153
+
154
+ Kamelopard.add_altitudeMode(@altitudeMode, e)
131
155
  end
156
+
157
+ d = REXML::Document.new
158
+ d.add_element e
159
+ d
132
160
  end
133
- k << "#{ ' ' * indent } <coordinates>#{ @longitude }, #{ @latitude }, #{ @altitude }</coordinates>\n"
134
- k << "#{ ' ' * indent }</Point>\n"
135
- k
136
161
  end
137
- end
138
162
 
139
- # Helper class for KML objects which need to know about several points at once
140
- class CoordinateList
141
- attr_reader :coordinates
142
-
143
- # Accepts an optional array of coordinates in any format add_element
144
- # accepts
145
- def initialize(coords = nil)
146
- # Internally we store coordinates as an array of three-element
147
- # arrays
148
- @coordinates = []
149
- if not coords.nil? then
150
- add_element coords
151
- else
163
+ # Helper class for KML objects which need to know about several points at once
164
+ class CoordinateList
165
+ attr_reader :coordinates
166
+
167
+ # Accepts an optional array of coordinates in any format add_element
168
+ # accepts
169
+ def initialize(coords = nil)
170
+ # Internally we store coordinates as an array of three-element
171
+ # arrays
152
172
  @coordinates = []
173
+ if not coords.nil? then
174
+ add_element coords
175
+ else
176
+ @coordinates = []
177
+ end
153
178
  end
154
- end
155
179
 
156
- def to_kml(indent = 0)
157
- k = "#{ ' ' * indent }<coordinates>\n#{ ' ' * indent } "
158
- if not @coordinates.nil? then
180
+ def to_kml(elem = nil)
181
+ e = REXML::Element.new 'coordinates'
182
+ t = ''
159
183
  @coordinates.each do |a|
160
- k << "#{ a[0] },#{ a[1] }"
161
- k << ",#{ a[2] }" if a.size > 2
162
- k << ' '
184
+ t << "#{ a[0] },#{ a[1] }"
185
+ t << ",#{ a[2] }" if a.size > 2
186
+ t << ' '
163
187
  end
188
+ e.text = t.chomp(' ')
189
+ elem.elements.add e unless elem.nil?
190
+ e
164
191
  end
165
- k << "\n#{ ' ' * indent}</coordinates>\n"
166
- k
167
- end
168
192
 
169
- # Alias for add_element
170
- def <<(a)
171
- add_element a
172
- end
193
+ # Alias for add_element
194
+ def <<(a)
195
+ add_element a
196
+ end
173
197
 
174
- # Adds one or more elements to this CoordinateList. The argument can be in any of several formats:
175
- # * An array of arrays of numeric objects, in the form [ longitude,
176
- # latitude, altitude (optional) ]
177
- # * A KMLPoint, or some other object that response to latitude, longitude, and altitude methods
178
- # * An array of the above
179
- # * Another CoordinateList, to append to this on
180
- # Note that this will not accept a one-dimensional array of numbers to add
181
- # a single point. Instead, create a KMLPoint with those numbers, and pass
182
- # it to add_element
183
- def add_element(a)
184
- if a.kind_of? Enumerable then
185
- # We've got some sort of array or list. It could be a list of
186
- # floats, to become one coordinate, or it could be several
187
- # coordinates
188
- t = a.to_a.first
189
- if t.kind_of? Enumerable then
190
- # At this point we assume we've got an array of float-like
191
- # objects. The second-level arrays need to have two or three
192
- # entries -- long, lat, and (optionally) alt
193
- a.each do |i|
194
- if i.size < 2 then
195
- raise "There aren't enough objects here to make a 2- or 3-element coordinate"
196
- elsif i.size >= 3 then
197
- @coordinates << [ i[0].to_f, i[1].to_f, i[2].to_f ]
198
- else
199
- @coordinates << [ i[0].to_f, i[1].to_f ]
198
+ # Adds one or more elements to this CoordinateList. The argument can be in any of several formats:
199
+ # * An array of arrays of numeric objects, in the form [ longitude,
200
+ # latitude, altitude (optional) ]
201
+ # * A Point, or some other object that response to latitude, longitude, and altitude methods
202
+ # * An array of the above
203
+ # * Another CoordinateList, to append to this on
204
+ # Note that this will not accept a one-dimensional array of numbers to add
205
+ # a single point. Instead, create a Point with those numbers, and pass
206
+ # it to add_element
207
+ def add_element(a)
208
+ if a.kind_of? Enumerable then
209
+ # We've got some sort of array or list. It could be a list of
210
+ # floats, to become one coordinate, or it could be several
211
+ # coordinates
212
+ t = a.to_a.first
213
+ if t.kind_of? Enumerable then
214
+ # At this point we assume we've got an array of float-like
215
+ # objects. The second-level arrays need to have two or three
216
+ # entries -- long, lat, and (optionally) alt
217
+ a.each do |i|
218
+ if i.size < 2 then
219
+ raise "There aren't enough objects here to make a 2- or 3-element coordinate"
220
+ elsif i.size >= 3 then
221
+ @coordinates << [ i[0].to_f, i[1].to_f, i[2].to_f ]
222
+ else
223
+ @coordinates << [ i[0].to_f, i[1].to_f ]
224
+ end
200
225
  end
226
+ elsif t.respond_to? 'longitude' and
227
+ t.respond_to? 'latitude' and
228
+ t.respond_to? 'altitude' then
229
+ # This object can cough up a set of coordinates
230
+ a.each do |i|
231
+ @coordinates << [i.longitude, i.latitude, i.altitude]
232
+ end
233
+ else
234
+ # I dunno what it is
235
+ raise "Kamelopard can't understand this object as a coordinate"
201
236
  end
202
- elsif t.respond_to? 'longitude' and
203
- t.respond_to? 'latitude' and
204
- t.respond_to? 'altitude' then
205
- # This object can cough up a set of coordinates
206
- a.each do |i|
207
- @coordinates << [i.longitude, i.latitude, i.altitude]
208
- end
237
+ elsif a.kind_of? CoordinateList then
238
+ # Append this coordinate list
239
+ @coordinates << a.coordinates
209
240
  else
210
- # I dunno what it is
211
- raise "Kamelopard can't understand this object as a coordinate"
212
- end
213
- elsif a.kind_of? CoordinateList then
214
- # Append this coordinate list
215
- @coordinates << a.coordinates
216
- else
217
- # This is one element. It better know how to make latitude, longitude, etc.
218
- if a.respond_to? 'longitude' and
219
- a.respond_to? 'latitude' and
220
- a.respond_to? 'altitude' then
221
- @coordinates << [a.longitude, a.latitude, a.altitude]
222
- else
223
- raise "Kamelopard can't understand this object as a coordinate"
241
+ # This is one element. It better know how to make latitude, longitude, etc.
242
+ if a.respond_to? 'longitude' and
243
+ a.respond_to? 'latitude' and
244
+ a.respond_to? 'altitude' then
245
+ @coordinates << [a.longitude, a.latitude, a.altitude]
246
+ else
247
+ raise "Kamelopard can't understand this object as a coordinate"
248
+ end
224
249
  end
225
250
  end
226
251
  end
227
- end
228
-
229
- # Corresponds to the KML LineString object
230
- class LineString < Geometry
231
- attr_accessor :altitudeOffset, :extrude, :tessellate, :altitudeMode, :drawOrder, :longitude, :latitude, :altitude
232
- attr_reader :coordinates
233
252
 
234
- def initialize(coords, altMode = :clampToGround)
235
- super()
236
- @altitudeMode = altMode
237
- set_coords coords
238
- end
253
+ # Corresponds to the KML LineString object
254
+ class LineString < Geometry
255
+ attr_accessor :altitudeOffset, :extrude, :tessellate, :altitudeMode, :drawOrder, :longitude, :latitude, :altitude
256
+ attr_reader :coordinates
239
257
 
240
- # Sets @coordinates element
241
- def set_coords(a)
242
- if a.kind_of? CoordinateList then
243
- @coordinates = a
244
- else
245
- @coordinates = CoordinateList.new(a)
258
+ def initialize(coords, altMode = :clampToGround)
259
+ super()
260
+ @altitudeMode = altMode
261
+ set_coords coords
246
262
  end
247
- end
248
-
249
- # Appends an element to this LineString's CoordinateList. See CoordinateList#add_element
250
- def <<(a)
251
- @coordinates << a
252
- end
253
263
 
254
- def to_kml(indent = 0)
255
-
256
- k = super(indent + 4) + "#{ ' ' * indent }<LineString id =\"#{ @id }\">\n"
257
- k << kml_array([
258
- [@altitudeOffset, 'gx:altitudeOffset', true],
259
- [@extrude, 'extrude', true],
260
- [@tessellate, 'tessellate', true],
261
- [@drawOrder, 'gx:drawOrder', true]
262
- ], indent + 4)
263
- k << @coordinates.to_kml(indent + 4) unless @coordinates.nil?
264
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
265
- k << "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
266
- else
267
- k << "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
264
+ # Sets @coordinates element
265
+ def set_coords(a)
266
+ if a.kind_of? CoordinateList then
267
+ @coordinates = a
268
+ else
269
+ @coordinates = CoordinateList.new(a)
270
+ end
268
271
  end
269
- k << "#{ ' ' * indent }</LineString>\n"
270
- k
271
- end
272
- end
273
272
 
274
- # Corresponds to KML's LinearRing object
275
- class LinearRing < Geometry
276
- attr_accessor :altitudeOffset, :extrude, :tessellate, :altitudeMode, :coordinates
277
-
278
- def initialize(coordinates = nil, tessellate = 0, extrude = 0, altitudeMode = :clampToGround, altitudeOffset = nil)
279
- super()
280
- if coordinates.nil? then
281
- @coordinates = nil
282
- elsif coordinates.kind_of? CoordinateList then
283
- @coordinates = coordinates
284
- else
285
- @coordinates = CoordinateList.new(coordinates)
273
+ # Appends an element to this LineString's CoordinateList. See CoordinateList#add_element
274
+ def <<(a)
275
+ @coordinates << a
286
276
  end
287
- @tessellate = tessellate
288
- @extrude = extrude
289
- @altitudeMode = altitudeMode
290
- @altitudeOffset = altitudeOffset
291
- end
292
277
 
293
- # Sets @coordinates element
294
- def set_coords(a)
295
- if a.kind_of? CoordinateList then
296
- @coordinates = a
297
- else
298
- @coordinates = CoordinateList.new(a)
278
+ def to_kml(elem = nil)
279
+ k = REXML::Element.new 'LineString'
280
+ super(k)
281
+ Kamelopard.kml_array(k, [
282
+ [@altitudeOffset, 'gx:altitudeOffset'],
283
+ [@extrude, 'extrude'],
284
+ [@tessellate, 'tessellate'],
285
+ [@drawOrder, 'gx:drawOrder']
286
+ ])
287
+ @coordinates.to_kml(k) unless @coordinates.nil?
288
+ Kamelopard.add_altitudeMode @altitudeMode, k
289
+ elem.elements << k unless elem.nil?
290
+ k
299
291
  end
300
292
  end
301
293
 
302
- # Appends an element to this LinearRing's CoordinateList. See CoordinateList#add_element
303
- def <<(a)
304
- @coordinates << a
305
- end
294
+ # Corresponds to KML's LinearRing object
295
+ class LinearRing < Geometry
296
+ attr_accessor :altitudeOffset, :extrude, :tessellate, :altitudeMode, :coordinates
306
297
 
307
- def to_kml(indent = 0)
308
- k = super(indent + 4) + "#{ ' ' * indent }<LinearRing id=\"#{ @id }\">\n"
309
- k << "#{ ' ' * indent } <gx:altitudeOffset>#{ @altitudeOffset }</gx:altitudeOffset>\n" unless @altitudeOffset.nil?
310
- k << "#{ ' ' * indent } <tessellate>#{ @tessellate }</tessellate>\n" unless @tessellate.nil?
311
- k << "#{ ' ' * indent } <extrude>#{ @extrude }</extrude>\n" unless @extrude.nil?
312
- if not @altitudeMode.nil? then
313
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
314
- k << "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
298
+ def initialize(coordinates = nil, tessellate = 0, extrude = 0, altitudeMode = :clampToGround, altitudeOffset = nil)
299
+ super()
300
+ if coordinates.nil? then
301
+ @coordinates = nil
302
+ elsif coordinates.kind_of? CoordinateList then
303
+ @coordinates = coordinates
315
304
  else
316
- k << "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
305
+ @coordinates = CoordinateList.new(coordinates)
317
306
  end
307
+ @tessellate = tessellate
308
+ @extrude = extrude
309
+ @altitudeMode = altitudeMode
310
+ @altitudeOffset = altitudeOffset
318
311
  end
319
- k << @coordinates.to_kml(indent + 4)
320
- k << "#{ ' ' * indent }</LinearRing>\n"
321
- k
322
- end
323
- end
324
312
 
325
- # Abstract class corresponding to KML's AbstractView object
326
- class AbstractView < KMLObject
327
- attr_accessor :timestamp, :timespan, :options, :point, :heading, :tilt, :roll, :range, :altitudeMode
328
- def initialize(className, point = nil, heading = 0, tilt = 0, roll = 0, range = 0, altitudeMode = :clampToGround)
329
- raise "className argument must not be nil" if className.nil?
330
- super()
331
- @point = point
332
- @options = {}
333
- @className = className
334
- if point.nil? then
335
- @point = nil
336
- elsif point.kind_of? Placemark then
337
- @point = point.point
338
- else
339
- @point = point
313
+ # Sets @coordinates element
314
+ def set_coords(a)
315
+ if a.kind_of? CoordinateList then
316
+ @coordinates = a
317
+ else
318
+ @coordinates = CoordinateList.new(a)
319
+ end
340
320
  end
341
- @heading = heading
342
- @tilt = tilt
343
- @roll = roll
344
- @range = range
345
- @altitudeMode = altitudeMode
346
- end
347
321
 
348
- def point=(point)
349
- @point.longitude = point.longitude
350
- @point.latitude = point.latitude
351
- @point.altitude = point.altitude
352
- end
322
+ # Appends an element to this LinearRing's CoordinateList. See CoordinateList#add_element
323
+ def <<(a)
324
+ @coordinates << a
325
+ end
353
326
 
354
- def longitude
355
- @point.nil? ? nil : @point.longitude
327
+ def to_kml(elem = nil)
328
+ k = REXML::Element.new 'LinearRing'
329
+ super(k)
330
+ Kamelopard.kml_array(k, [
331
+ [ @altitudeOffset, 'gx:altitudeOffset' ],
332
+ [ @tessellate, 'tessellate' ],
333
+ [ @extrude, 'extrude' ]
334
+ ])
335
+ Kamelopard.add_altitudeMode(@altitudeMode, k)
336
+ @coordinates.to_kml(k)
337
+ elem.elements << k unless elem.nil?
338
+ k
339
+ end
356
340
  end
357
341
 
358
- def latitude
359
- @point.nil? ? nil : @point.latitude
360
- end
342
+ # Abstract class corresponding to KML's AbstractView object
343
+ class AbstractView < Object
344
+ attr_accessor :timestamp, :timespan, :options, :point, :heading, :tilt, :roll, :range, :altitudeMode
345
+ def initialize(className, point = nil, heading = 0, tilt = 0, roll = 0, range = 0, altitudeMode = :clampToGround)
346
+ raise "className argument must not be nil" if className.nil?
347
+ super()
348
+ @point = point
349
+ @options = {}
350
+ @className = className
351
+ if point.nil? then
352
+ @point = nil
353
+ elsif point.kind_of? Placemark then
354
+ @point = point.point
355
+ else
356
+ @point = point
357
+ end
358
+ @heading = heading
359
+ @tilt = tilt
360
+ @roll = roll
361
+ @range = range
362
+ @altitudeMode = altitudeMode
363
+ end
361
364
 
362
- def altitude
363
- @point.nil? ? nil : @point.altitude
364
- end
365
+ def point=(point)
366
+ @point.longitude = point.longitude
367
+ @point.latitude = point.latitude
368
+ @point.altitude = point.altitude
369
+ end
365
370
 
366
- def longitude=(a)
367
- if @point.nil? then
368
- @point = KMLPoint.new(a, 0)
369
- else
370
- @point.longitude = a
371
+ def longitude
372
+ @point.nil? ? nil : @point.longitude
371
373
  end
372
- end
373
374
 
374
- def latitude=(a)
375
- if @point.nil? then
376
- @point = KMLPoint.new(0, a)
377
- else
378
- @point.latitude = a
375
+ def latitude
376
+ @point.nil? ? nil : @point.latitude
379
377
  end
380
- end
381
378
 
382
- def altitude=(a)
383
- if @point.nil? then
384
- @point = KMLPoint.new(0, 0, a)
385
- else
386
- @point.altitude = a
379
+ def altitude
380
+ @point.nil? ? nil : @point.altitude
387
381
  end
388
- end
389
382
 
390
- def to_kml(indent = 0)
391
- t = "#{ ' ' * indent }<#{ @className } id=\"#{ @id }\">\n"
392
- t << super(indent)
393
- t << kml_array([
394
- [ @point.nil? ? nil : @point.longitude, 'longitude', true ],
395
- [ @point.nil? ? nil : @point.latitude, 'latitude', true ],
396
- [ @point.nil? ? nil : @point.altitude, 'altitude', true ],
397
- [ @heading, 'heading', true ],
398
- [ @tilt, 'tilt', true ],
399
- [ @range, 'range', true ],
400
- [ @roll, 'roll', true ]
401
- ], indent + 4)
402
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
403
- t << "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
404
- else
405
- t << "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
383
+ def longitude=(a)
384
+ if @point.nil? then
385
+ @point = Point.new(a, 0)
386
+ else
387
+ @point.longitude = a
388
+ end
406
389
  end
407
- if @options.keys.length > 0 then
408
- t << "#{ ' ' * indent } <gx:ViewerOptions>\n"
409
- @options.each do |k, v|
410
- t << "#{ ' ' * ( indent + 8 ) }<gx:option name=\"#{ k }\" enabled=\"#{ v ? 'true' : 'false' }\" />\n"
390
+
391
+ def latitude=(a)
392
+ if @point.nil? then
393
+ @point = Point.new(0, a)
394
+ else
395
+ @point.latitude = a
411
396
  end
412
- t << "#{ ' ' * indent } </gx:ViewerOptions>\n"
413
397
  end
414
- if not @timestamp.nil? then
415
- t << @timestamp.to_kml(indent+4, 'gx')
416
- elsif not @timespan.nil? then
417
- t << @timespan.to_kml(indent+4, 'gx')
398
+
399
+ def altitude=(a)
400
+ if @point.nil? then
401
+ @point = Point.new(0, 0, a)
402
+ else
403
+ @point.altitude = a
404
+ end
418
405
  end
419
- t << "#{ ' ' * indent }</#{ @className }>\n"
420
- t
421
- end
422
406
 
423
- def [](a)
424
- return @options[a]
425
- end
407
+ def to_kml(elem = nil)
408
+ t = REXML::Element.new @className
409
+ super(t)
410
+ Kamelopard.kml_array(t, [
411
+ [ @point.nil? ? nil : @point.longitude, 'longitude' ],
412
+ [ @point.nil? ? nil : @point.latitude, 'latitude' ],
413
+ [ @point.nil? ? nil : @point.altitude, 'altitude' ],
414
+ [ @heading, 'heading' ],
415
+ [ @tilt, 'tilt' ],
416
+ [ @range, 'range' ],
417
+ [ @roll, 'roll' ]
418
+ ])
419
+ Kamelopard.add_altitudeMode(@altitudeMode, t)
420
+ if @options.keys.length > 0 then
421
+ vo = REXML::Element.new 'gx:ViewerOptions'
422
+ @options.each do |k, v|
423
+ o = REXML::Element.new 'gx:option'
424
+ o.attributes['name'] = k
425
+ o.attributes['enabled'] = v ? 'true' : 'false'
426
+ vo.elements << o
427
+ end
428
+ t.elements << vo
429
+ end
430
+ if not @timestamp.nil? then
431
+ @timestamp.to_kml(t, 'gx')
432
+ elsif not @timespan.nil? then
433
+ @timespan.to_kml(t, 'gx')
434
+ end
435
+ elem.elements << t unless elem.nil?
436
+ t
437
+ end
426
438
 
427
- def []=(a, b)
428
- if not b.kind_of? FalseClass and not b.kind_of? TrueClass then
429
- raise 'Option value must be boolean'
439
+ def [](a)
440
+ return @options[a]
430
441
  end
431
- if a != :streetview and a != :historicalimagery and a != :sunlight then
432
- raise 'Option index must be :streetview, :historicalimagery, or :sunlight'
442
+
443
+ def []=(a, b)
444
+ if not b.kind_of? FalseClass and not b.kind_of? TrueClass then
445
+ raise 'Option value must be boolean'
446
+ end
447
+ if a != :streetview and a != :historicalimagery and a != :sunlight then
448
+ raise 'Option index must be :streetview, :historicalimagery, or :sunlight'
449
+ end
450
+ @options[a] = b
433
451
  end
434
- @options[a] = b
435
452
  end
436
- end
437
453
 
438
- # Corresponds to KML's Camera object
439
- class Camera < AbstractView
440
- def initialize(point = nil, heading = 0, tilt = 0, roll = 0, altitudeMode = :clampToGround)
441
- super('Camera', point, heading, tilt, roll, nil, altitudeMode)
442
- end
454
+ # Corresponds to KML's Camera object
455
+ class Camera < AbstractView
456
+ def initialize(point = nil, heading = 0, tilt = 0, roll = 0, altitudeMode = :clampToGround)
457
+ super('Camera', point, heading, tilt, roll, nil, altitudeMode)
458
+ end
443
459
 
444
- def range
445
- raise "The range element is part of LookAt objects, not Camera objects"
446
- end
460
+ def range
461
+ raise "The range element is part of LookAt objects, not Camera objects"
462
+ end
447
463
 
448
- def range=
449
- # The range element doesn't exist in Camera objects
464
+ def range=
465
+ # The range element doesn't exist in Camera objects
466
+ end
450
467
  end
451
- end
452
468
 
453
- # Corresponds to KML's LookAt object
454
- class LookAt < AbstractView
455
- def initialize(point = nil, heading = 0, tilt = 0, range = 0, altitudeMode = :clampToGround)
456
- super('LookAt', point, heading, tilt, nil, range, altitudeMode)
457
- end
469
+ # Corresponds to KML's LookAt object
470
+ class LookAt < AbstractView
471
+ def initialize(point = nil, heading = 0, tilt = 0, range = 0, altitudeMode = :clampToGround)
472
+ super('LookAt', point, heading, tilt, nil, range, altitudeMode)
473
+ end
458
474
 
459
- def roll
460
- raise "The roll element is part of Camera objects, not LookAt objects"
461
- end
475
+ def roll
476
+ raise "The roll element is part of Camera objects, not LookAt objects"
477
+ end
462
478
 
463
- def roll=
464
- # The roll element doesn't exist in LookAt objects
479
+ def roll=
480
+ # The roll element doesn't exist in LookAt objects
481
+ end
465
482
  end
466
- end
467
483
 
468
- # Abstract class corresponding to KML's TimePrimitive object
469
- class TimePrimitive < KMLObject
470
- end
471
-
472
- # Corresponds to KML's TimeStamp object. The @when attribute must be in a format KML understands.
473
- class TimeStamp < TimePrimitive
474
- attr_accessor :when
475
- def initialize(t_when)
476
- super()
477
- @when = t_when
484
+ # Abstract class corresponding to KML's TimePrimitive object
485
+ class TimePrimitive < Object
478
486
  end
479
487
 
480
- def to_kml(indent = 0, ns = nil)
481
- prefix = ''
482
- prefix = ns + ':' unless ns.nil?
483
-
484
- k = super(indent + 4)
485
- k << <<-timestamp
486
- #{ ' ' * indent }<#{ prefix }TimeStamp id="#{ @id }">
487
- #{ ' ' * indent } <when>#{ @when }</when>
488
- #{ ' ' * indent }</#{ prefix }TimeStamp>
489
- timestamp
490
- end
491
- end
488
+ # Corresponds to KML's TimeStamp object. The @when attribute must be in a format KML understands.
489
+ class TimeStamp < TimePrimitive
490
+ attr_accessor :when
491
+ def initialize(t_when)
492
+ super()
493
+ @when = t_when
494
+ end
492
495
 
493
- # Corresponds to KML's TimeSpan object. @begin and @end must be in a format KML
494
- # understands.
495
- class TimeSpan < TimePrimitive
496
- attr_accessor :begin, :end
497
- def initialize(t_begin, t_end)
498
- super()
499
- @begin = t_begin
500
- @end = t_end
496
+ def to_kml(elem = nil, ns = nil)
497
+ prefix = ''
498
+ prefix = ns + ':' unless ns.nil?
499
+
500
+ k = REXML::Element.new "#{prefix}TimeStamp"
501
+ super(k)
502
+ w = REXML::Element.new 'when'
503
+ w.text = @when
504
+ k.elements << w
505
+ elem.elements << k unless elem.nil?
506
+ k
507
+ end
501
508
  end
502
509
 
503
- def to_kml(indent = 0, ns = nil)
504
- prefix = ''
505
- prefix = ns + ':' unless ns.nil?
510
+ # Corresponds to KML's TimeSpan object. @begin and @end must be in a format KML
511
+ # understands.
512
+ class TimeSpan < TimePrimitive
513
+ attr_accessor :begin, :end
514
+ def initialize(t_begin, t_end)
515
+ super()
516
+ @begin = t_begin
517
+ @end = t_end
518
+ end
506
519
 
507
- k = super(indent + 4) + "#{ ' ' * indent }<#{ prefix }TimeSpan id=\"#{ @id }\">\n"
508
- k << "#{ ' ' * indent } <begin>#{ @begin }</begin>\n" unless @begin.nil?
509
- k << "#{ ' ' * indent } <end>#{ @end }</end>\n" unless @end.nil?
510
- k << "#{ ' ' * indent }</#{ prefix }TimeSpan>\n"
511
- k
520
+ def to_kml(elem = nil, ns = nil)
521
+ prefix = ''
522
+ prefix = ns + ':' unless ns.nil?
523
+
524
+ k = REXML::Element.new "#{prefix}TimeSpan"
525
+ super(k)
526
+ if not @begin.nil? then
527
+ w = REXML::Element.new 'begin'
528
+ w.text = @begin
529
+ k.elements << w
530
+ end
531
+ if not @end.nil? then
532
+ w = REXML::Element.new 'end'
533
+ w.text = @end
534
+ k.elements << w
535
+ elem.elements << k unless elem.nil?
536
+ end
537
+ k
538
+ end
512
539
  end
513
- end
514
540
 
515
- # Support class for Feature object
516
- class Snippet
517
- attr_accessor :text, :maxLines
518
- def initialize(text = nil, maxLines = 2)
519
- @text = text
520
- @maxLines = maxLines
521
- end
541
+ # Support class for Feature object
542
+ class Snippet
543
+ attr_accessor :text, :maxLines
544
+ def initialize(text = nil, maxLines = 2)
545
+ @text = text
546
+ @maxLines = maxLines
547
+ end
522
548
 
523
- def to_kml(indent = 0)
524
- k = "#{ ' ' * indent }<Snippet maxLines=\"#{maxLines}\">"
525
- k << text
526
- k << "#{ ' ' * indent }</Snippet>\n"
549
+ def to_kml(elem = nil)
550
+ e = REXML::Element.new 'Snippet'
551
+ e.attributes['maxLines'] = @maxLines
552
+ e.text = @text
553
+ elem.elements << e unless elem.nil?
554
+ e
555
+ end
527
556
  end
528
- end
529
557
 
530
- # Abstract class corresponding to KML's Feature object.
531
- class Feature < KMLObject
532
- # Abstract class
533
- attr_accessor :visibility, :open, :atom_author, :atom_link, :name,
534
- :phoneNumber, :snippet, :description, :abstractView,
535
- :timeprimitive, :styleUrl, :styleSelector, :region, :metadata,
536
- :extendedData, :styles
537
- attr_reader :addressDetails
538
-
539
- def initialize (name = nil)
540
- super()
541
- @name = name
542
- @visibility = true
543
- @open = false
544
- @styles = []
545
- end
558
+ # Abstract class corresponding to KML's Feature object.
559
+ class Feature < Object
560
+ # Abatract class
561
+ attr_accessor :visibility, :open, :atom_author, :atom_link, :name,
562
+ :phoneNumber, :snippet, :description, :abstractView,
563
+ :timeprimitive, :styleUrl, :styleSelector, :region, :metadata,
564
+ :extendedData, :styles
565
+ attr_reader :addressDetails
566
+
567
+ def initialize (name = nil)
568
+ super()
569
+ @name = name
570
+ @visibility = true
571
+ @open = false
572
+ @styles = []
573
+ end
546
574
 
547
- def timestamp
548
- @timeprimitive
549
- end
575
+ def timestamp
576
+ @timeprimitive
577
+ end
550
578
 
551
- def timespan
552
- @timeprimitive
553
- end
579
+ def timespan
580
+ @timeprimitive
581
+ end
554
582
 
555
- def timestamp=(t)
556
- @timeprimitive = t
557
- end
583
+ def timestamp=(t)
584
+ @timeprimitive = t
585
+ end
558
586
 
559
- def timespan=(t)
560
- @timeprimitive = t
561
- end
587
+ def timespan=(t)
588
+ @timeprimitive = t
589
+ end
562
590
 
563
- def addressDetails=(a)
564
- if a.nil? or a == '' then
565
- Document.instance.uses_xal = false
566
- else
567
- Document.instance.uses_xal = true
591
+ def addressDetails=(a)
592
+ if a.nil? or a == '' then
593
+ Document.instance.uses_xal = false
594
+ else
595
+ Document.instance.uses_xal = true
596
+ end
597
+ @addressDetails = a
568
598
  end
569
- @addressDetails = a
570
- end
571
599
 
572
- # This function accepts either a StyleSelector object, or a string
573
- # containing the desired StyleSelector's @id
574
- def styleUrl=(a)
575
- if a.is_a? String then
576
- @styleUrl = a
577
- elsif a.respond_to? 'id' then
578
- @styleUrl = "##{ a.id }"
579
- else
580
- @styleUrl = a.to_s
600
+ # This function accepts either a StyleSelector object, or a string
601
+ # containing the desired StyleSelector's @id
602
+ def styleUrl=(a)
603
+ if a.is_a? String then
604
+ @styleUrl = a
605
+ elsif a.respond_to? 'id' then
606
+ @styleUrl = "##{ a.id }"
607
+ else
608
+ @styleUrl = a.to_s
609
+ end
581
610
  end
582
- end
583
611
 
584
- def to_kml(indent = 0)
585
- k = ''
586
- if self.class == Feature then k << "#{ ' ' * indent }<Feature id=\"#{ @id }\">\n" end
587
- k << super
588
- k << kml_array([
589
- [@name, 'name', true],
590
- [(@visibility.nil? || @visibility) ? 1 : 0, 'visibility', true],
591
- [(! @open.nil? && @open) ? 1 : 0, 'open', true],
592
- [@atom_author, "<atom:author><atom:name>#{ @atom_author }</atom:name></atom:author>", false],
593
- [@atom_link, 'atom:link', true],
594
- [@address, 'address', true],
595
- [@addressDetails, 'xal:AddressDetails', true],
596
- [@phoneNumber, 'phoneNumber', true],
597
- [@description, 'description', true],
598
- [@styleUrl, 'styleUrl', true],
599
- [@styleSelector, "<styleSelector>#{@styleSelector.nil? ? '' : @styleSelector.to_kml}</styleSelector>", false ],
600
- [@metadata, 'Metadata', true ],
601
- [@extendedData, 'ExtendedData', true ]
602
- ], (indent))
603
- k << styles_to_kml(indent)
604
- k << @snippet.to_kml(indent) unless @snippet.nil?
605
- k << @abstractView.to_kml(indent) unless @abstractView.nil?
606
- k << @timeprimitive.to_kml(indent) unless @timeprimitive.nil?
607
- k << @region.to_kml(indent) unless @region.nil?
608
- k << yield if block_given?
609
- if self.class == Feature then k << "#{ ' ' * indent }</Feature>\n" end
610
- k
611
- end
612
-
613
- def styles_to_kml(indent = 0)
614
- k = ''
615
- @styles.each do |a|
616
- k << a.to_kml(indent)
612
+ def self.add_author(o, a)
613
+ e = REXML::Element.new 'atom:name'
614
+ e.text = a
615
+ f = REXML::Element.new 'atom:author'
616
+ f << e
617
+ o << f
617
618
  end
618
- k
619
- end
620
- end
621
619
 
622
- # Abstract class corresponding to KML's Container object.
623
- class Container < Feature
624
- def initialize
625
- super
626
- @features = []
620
+ def to_kml(elem = nil)
621
+ elem = REXML::Element.new 'Feature' if elem.nil?
622
+ super(elem)
623
+ Kamelopard.kml_array(elem, [
624
+ [@name, 'name'],
625
+ [(@visibility.nil? || @visibility) ? 1 : 0, 'visibility'],
626
+ [(! @open.nil? && @open) ? 1 : 0, 'open'],
627
+ [@atom_author, lambda { |o| Feature.add_author(o, @atom_author) }],
628
+ [@atom_link, 'atom:link'],
629
+ [@address, 'address'],
630
+ [@addressDetails, 'xal:AddressDetails'],
631
+ [@phoneNumber, 'phoneNumber'],
632
+ [@description, 'description'],
633
+ [@styleUrl, 'styleUrl'],
634
+ [@styleSelector, lambda { |o| @styleSelector.to_kml(o) }],
635
+ [@metadata, 'Metadata' ],
636
+ [@extendedData, 'ExtendedData' ]
637
+ ])
638
+ styles_to_kml(elem)
639
+ @snippet.to_kml(elem) unless @snippet.nil?
640
+ @abstractView.to_kml(elem) unless @abstractView.nil?
641
+ @timeprimitive.to_kml(elem) unless @timeprimitive.nil?
642
+ @region.to_kml(elem) unless @region.nil?
643
+ yield(elem) if block_given?
644
+ elem
645
+ end
646
+
647
+ def styles_to_kml(elem)
648
+ @styles.each do |a|
649
+ a.to_kml(elem)
650
+ end
651
+ end
627
652
  end
628
653
 
629
- # Adds a new object to this container.
630
- def <<(a)
631
- @features << a
654
+ # Abstract class corresponding to KML's Container object.
655
+ class Container < Feature
656
+ def initialize
657
+ super
658
+ @features = []
659
+ end
660
+
661
+ # Adds a new object to this container.
662
+ def <<(a)
663
+ @features << a
664
+ end
632
665
  end
633
- end
634
666
 
635
- # Corresponds to KML's Folder object.
636
- class Folder < Container
637
- attr_accessor :styles, :folders, :parent_folder
667
+ # Corresponds to KML's Folder object.
668
+ class Folder < Container
669
+ attr_accessor :styles, :folders, :parent_folder
638
670
 
639
- def initialize(name = nil)
640
- super()
641
- @name = name
642
- @styles = []
643
- @folders = []
644
- Document.instance.folders << self
645
- end
671
+ def initialize(name = nil)
672
+ super()
673
+ @name = name
674
+ @styles = []
675
+ @folders = []
676
+ Document.instance.folders << self
677
+ end
646
678
 
647
- def to_kml(indent = 0)
648
- h = "#{ ' ' * indent }<Folder id=\"#{@id}\">\n"
649
- h << super(indent + 4)
650
- @features.each do |a|
651
- h << a.to_kml(indent + 4)
679
+ def to_kml(elem = nil)
680
+ h = REXML::Element.new 'Folder'
681
+ super h
682
+ @features.each do |a|
683
+ a.to_kml(h)
684
+ end
685
+ @folders.each do |a|
686
+ a.to_kml(h)
687
+ end
688
+ elem.elements << h unless elem.nil?
689
+ h
652
690
  end
653
- @folders.each do |a|
654
- h << a.to_kml(indent + 4)
691
+
692
+ # Folders can have parent folders; returns true if this folder has one
693
+ def has_parent?
694
+ not @parent_folder.nil?
655
695
  end
656
- h << "#{ ' ' * indent }</Folder>\n";
657
- h
658
- end
659
696
 
660
- # Folders can have parent folders; returns true if this folder has one
661
- def has_parent?
662
- not @parent_folder.nil?
697
+ # Folders can have parent folders; sets this folder's parent
698
+ def parent_folder=(a)
699
+ @parent_folder = a
700
+ a.folders << self
701
+ end
663
702
  end
664
703
 
665
- # Folders can have parent folders; sets this folder's parent
666
- def parent_folder=(a)
667
- @parent_folder = a
668
- a.folders << self
704
+ def get_stack_trace # :nodoc
705
+ k = ''
706
+ caller.each do |a| k << "#{a}\n" end
707
+ k
669
708
  end
670
- end
671
709
 
672
- def get_stack_trace # :nodoc
673
- k = ''
674
- caller.each do |a| k << "#{a}\n" end
675
- k
676
- end
710
+ # Represents KML's Document class. This is a Singleton object; Kamelopard
711
+ # scripts can (for now) manage only one Document at a time.
712
+ class Document < Container
713
+ include Singleton
714
+ attr_accessor :flyto_mode, :folders, :tours, :uses_xal
677
715
 
678
- # Represents KML's Document class. This is a Singleton object; Kamelopard
679
- # scripts can (for now) manage only one Document at a time.
680
- class Document < Container
681
- include Singleton
682
- attr_accessor :flyto_mode, :folders, :tours, :uses_xal
683
-
684
- def initialize
685
- @tours = []
686
- @folders = []
687
- @styles = []
688
- end
716
+ def initialize
717
+ super
718
+ @tours = []
719
+ @folders = []
720
+ @styles = []
721
+ end
689
722
 
690
- # Returns the current Tour object
691
- def tour
692
- @tours << Tour.new if @tours.length == 0
693
- @tours.last
694
- end
723
+ # Returns the current Tour object
724
+ def tour
725
+ @tours << Tour.new if @tours.length == 0
726
+ @tours.last
727
+ end
695
728
 
696
- # Returns the current Folder object
697
- def folder
698
- if @folders.size == 0 then
699
- Folder.new
729
+ # Returns the current Folder object
730
+ def folder
731
+ if @folders.size == 0 then
732
+ Folder.new
733
+ end
734
+ @folders.last
700
735
  end
701
- @folders.last
702
- end
703
736
 
704
- def styles_to_kml(indent)
705
- ''
706
- end
737
+ # def styles_to_kml(elem = nil)
738
+ # end
707
739
 
708
- def to_kml
709
- xal = ''
710
- if @uses_xal then
711
- xal = ' xmlns:xal="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"'
740
+ def get_kml_document
741
+ k = REXML::Document.new
742
+ k << REXML::XMLDecl.default
743
+ r = REXML::Element.new('kml')
744
+ if @uses_xal then
745
+ r.attributes['xmlns:xal'] = "urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"
746
+ end
747
+ # XXX Should this be add_namespace instead?
748
+ r.attributes['xmlns'] = 'http://www.opengis.net/kml/2.2'
749
+ r.attributes['xmlns:gx'] = 'http://www.google.com/kml/ext/2.2'
750
+ r.attributes['xmlns:kml'] = 'http://www.opengis.net/kml/2.2'
751
+ r.attributes['xmlns:atom'] = 'http://www.w3.org/2005/Atom'
752
+ r.elements << self.to_kml
753
+ k << r
754
+ k
712
755
  end
713
- h = <<-doc_header
714
- <?xml version="1.0" encoding="UTF-8"?>
715
- <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"#{ xal }>
716
- <Document>
717
- doc_header
718
-
719
- h << super(4)
720
756
 
721
- # Print styles first
722
- @styles.map do |a| h << a.to_kml(4) unless a.attached? end
757
+ def to_kml
758
+ d = REXML::Element.new 'Document'
759
+ super(d)
723
760
 
724
- # then folders
725
- @folders.map do |a| h << a.to_kml(4) unless a.has_parent? end
761
+ # Print styles first
762
+ @styles.map do |a| a.to_kml(d) unless a.attached? end
726
763
 
727
- # then tours
728
- @tours.map do |a| h << a.to_kml(4) end
729
- h << "</Document>\n</kml>\n"
764
+ # then folders
765
+ @folders.map do |a|
766
+ a.to_kml(d) unless a.has_parent?
767
+ end
730
768
 
731
- h
732
- end
733
- end
769
+ # then tours
770
+ @tours.map do |a| a.to_kml(d) end
734
771
 
735
- # Corresponds to KML's ColorStyle object. Color is stored as an 8-character hex
736
- # string, with two characters each of alpha, blue, green, and red values, in
737
- # that order, matching the ordering the KML spec demands.
738
- class ColorStyle < KMLObject
739
- attr_accessor :color
740
- attr_reader :colormode
741
-
742
- def initialize(color, colormode = :normal)
743
- super()
744
- # Note: color element order is aabbggrr
745
- @color = color
746
- validate_colormode colormode
747
- @colormode = colormode # Can be :normal or :random
772
+ d
773
+ end
748
774
  end
749
775
 
750
- def validate_colormode(a)
751
- raise "colorMode must be either \"normal\" or \"random\"" unless a == :normal or a == :random
752
- end
776
+ # Corresponds to KML's ColorStyle object. Color is stored as an 8-character hex
777
+ # string, with two characters each of alpha, blue, green, and red values, in
778
+ # that order, matching the ordering the KML spec demands.
779
+ class ColorStyle < Object
780
+ attr_accessor :color
781
+ attr_reader :colorMode
782
+
783
+ def initialize(color, colorMode = :normal)
784
+ super()
785
+ # Note: color element order is aabbggrr
786
+ @color = color
787
+ validate_colorMode colorMode
788
+ @colorMode = colorMode # Can be :normal or :random
789
+ end
753
790
 
754
- def colormode=(a)
755
- validate_colormode a
756
- @colormode = a
757
- end
791
+ def validate_colorMode(a)
792
+ raise "colorMode must be either \"normal\" or \"random\"" unless a == :normal or a == :random
793
+ end
758
794
 
759
- def alpha
760
- @color[0,1]
761
- end
795
+ def colorMode=(a)
796
+ validate_colorMode a
797
+ @colorMode = a
798
+ end
762
799
 
763
- def alpha=(a)
764
- @color[0,1] = a
765
- end
800
+ def alpha
801
+ @color[0,2]
802
+ end
766
803
 
767
- def blue
768
- @color[2,1]
769
- end
804
+ def alpha=(a)
805
+ @color[0,2] = a
806
+ end
770
807
 
771
- def blue=(a)
772
- @color[2,1] = a
773
- end
808
+ def blue
809
+ @color[2,2]
810
+ end
774
811
 
775
- def green
776
- @color[4,1]
777
- end
812
+ def blue=(a)
813
+ @color[2,2] = a
814
+ end
778
815
 
779
- def green=(a)
780
- @color[4,1] = a
781
- end
816
+ def green
817
+ @color[4,2]
818
+ end
782
819
 
783
- def red
784
- @color[6,1]
785
- end
820
+ def green=(a)
821
+ @color[4,2] = a
822
+ end
786
823
 
787
- def red=(a)
788
- @color[6,1] = a
789
- end
824
+ def red
825
+ @color[6,2]
826
+ end
790
827
 
791
- def to_kml(indent = 0)
828
+ def red=(a)
829
+ @color[6,2] = a
830
+ end
792
831
 
793
- super + <<-colorstyle
794
- #{ ' ' * indent }<color>#{@color}</color>
795
- #{ ' ' * indent }<colorMode>#{@colormode}</colorMode>
796
- colorstyle
832
+ def to_kml(elem = nil)
833
+ k = elem.nil? ? REXML::Element.new('ColorStyle') : elem
834
+ super k
835
+ e = REXML::Element.new 'color'
836
+ e.text = @color
837
+ k.elements << e
838
+ e = REXML::Element.new 'colorMode'
839
+ e.text = @colorMode
840
+ k.elements << e
841
+ k
842
+ end
797
843
  end
798
- end
799
844
 
800
- # Corresponds to KML's BalloonStyle object. Color is stored as an 8-character hex
801
- # string, with two characters each of alpha, blue, green, and red values, in
802
- # that order, matching the ordering the KML spec demands.
803
- class BalloonStyle < ColorStyle
804
- attr_accessor :bgcolor, :text, :textcolor, :displaymode
805
-
806
- # Note: color element order is aabbggrr
807
- def initialize(text = '', textcolor = 'ff000000', bgcolor = 'ffffffff', displaymode = :default)
808
- super(nil, :normal)
809
- @bgcolor = bgcolor
810
- @text = text
811
- @textcolor = textcolor
812
- @displaymode = displaymode
813
- end
845
+ # Corresponds to KML's BalloonStyle object. Color is stored as an 8-character hex
846
+ # string, with two characters each of alpha, blue, green, and red values, in
847
+ # that order, matching the ordering the KML spec demands.
848
+ class BalloonStyle < Object
849
+ attr_accessor :bgColor, :text, :textColor, :displayMode
814
850
 
815
- def to_kml(indent = 0)
816
- super + <<-balloonstyle
817
- #{ ' ' * indent }<BalloonStyle id="#{@id}">
818
- #{ ' ' * indent } <bgColor>#{@bgcolor}</bgColor>
819
- #{ ' ' * indent } <text>#{@text}</text>
820
- #{ ' ' * indent } <textColor>#{@textcolor}</textColor>
821
- #{ ' ' * indent } <displayMode>#{@displaymode}</displayMode>
822
- #{ ' ' * indent }</BalloonStyle>
823
- balloonstyle
824
- end
825
- end
851
+ # Note: color element order is aabbggrr
852
+ def initialize(text = '', textColor = 'ff000000', bgColor = 'ffffffff', displayMode = :default)
853
+ super()
854
+ @bgColor = bgColor
855
+ @text = text
856
+ @textColor = textColor
857
+ @displayMode = displayMode
858
+ end
826
859
 
827
- # Internal class used where KML requires X and Y values and units
828
- class KMLxy
829
- attr_accessor :x, :y, :xunits, :yunits
830
- def initialize(x = 0.5, y = 0.5, xunits = :fraction, yunits = :fraction)
831
- @x = x
832
- @y = y
833
- @xunits = xunits
834
- @yunits = yunits
860
+ def to_kml(elem = nil)
861
+ k = REXML::Element.new 'BalloonStyle'
862
+ super k
863
+ Kamelopard.kml_array(k, [
864
+ [ @bgColor, 'bgColor' ],
865
+ [ @text, 'text' ],
866
+ [ @textColor, 'textColor' ],
867
+ [ @displayMode, 'displayMode' ]
868
+ ])
869
+ elem << k unless elem.nil?
870
+ k
871
+ end
835
872
  end
836
873
 
837
- def to_kml(name, indent = 0)
874
+ # Internal class used where KML requires X and Y values and units
875
+ class XY
876
+ attr_accessor :x, :y, :xunits, :yunits
877
+ def initialize(x = 0.5, y = 0.5, xunits = :fraction, yunits = :fraction)
878
+ @x = x
879
+ @y = y
880
+ @xunits = xunits
881
+ @yunits = yunits
882
+ end
838
883
 
839
- <<-kmlxy
840
- #{ ' ' * indent}<#{ name } x="#{ @x }" y="#{ @y }" xunits="#{ @xunits }" yunits="#{ @yunits }" />
841
- kmlxy
884
+ def to_kml(name, elem = nil)
885
+ k = REXML::Element.new name
886
+ k.attributes['x'] = @x
887
+ k.attributes['y'] = @y
888
+ k.attributes['xunits'] = @xunits
889
+ k.attributes['yunits'] = @yunits
890
+ elem.elements << k unless elem.nil?
891
+ k
892
+ end
842
893
  end
843
- end
844
894
 
845
- # Corresponds to the KML Icon object
846
- class Icon
847
- attr_accessor :href, :x, :y, :w, :h, :refreshMode, :refreshInterval, :viewRefreshMode, :viewRefreshTime, :viewBoundScale, :viewFormat, :httpQuery
895
+ # Corresponds to the KML Icon object
896
+ class Icon
897
+ attr_accessor :id, :href, :x, :y, :w, :h, :refreshMode, :refreshInterval, :viewRefreshMode, :viewRefreshTime, :viewBoundScale, :viewFormat, :httpQuery
848
898
 
849
- def initialize(href = nil)
850
- @href = href
851
- end
899
+ def initialize(href = nil)
900
+ @href = href
901
+ @id = "Icon_#{ Kamelopard.get_next_id }"
902
+ end
852
903
 
853
- def to_kml(indent = 0)
854
- k = "#{ ' ' * indent }<Icon>\n"
855
- k << kml_array([
856
- [@href, 'href', true],
857
- [@x, 'gx:x', true],
858
- [@y, 'gx:y', true],
859
- [@w, 'gx:w', true],
860
- [@h, 'gx:h', true],
861
- [@refreshMode, 'refreshMode', true],
862
- [@refreshInterval, 'refreshInterval', true],
863
- [@viewRefreshMode, 'viewRefreshMode', true],
864
- [@viewBoundScale, 'viewBoundScale', true],
865
- [@viewFormat, 'viewFormat', true],
866
- [@httpQuery, 'httpQuery', true],
867
- ], indent + 4)
868
- k << "#{ ' ' * indent }</Icon>\n"
904
+ def to_kml(elem = nil)
905
+ k = REXML::Element.new 'Icon'
906
+ k.attributes['id'] = @id
907
+ Kamelopard.kml_array(k, [
908
+ [@href, 'href'],
909
+ [@x, 'gx:x'],
910
+ [@y, 'gx:y'],
911
+ [@w, 'gx:w'],
912
+ [@h, 'gx:h'],
913
+ [@refreshMode, 'refreshMode'],
914
+ [@refreshInterval, 'refreshInterval'],
915
+ [@viewRefreshMode, 'viewRefreshMode'],
916
+ [@viewRefreshTime, 'viewRefreshTime'],
917
+ [@viewBoundScale, 'viewBoundScale'],
918
+ [@viewFormat, 'viewFormat'],
919
+ [@httpQuery, 'httpQuery'],
920
+ ])
921
+ elem.elements << k unless elem.nil?
922
+ k
923
+ end
869
924
  end
870
- end
871
925
 
872
- # Corresponds to KML's IconStyle object.
873
- class IconStyle < ColorStyle
874
- attr_accessor :scale, :heading, :hotspot, :icon
926
+ # Corresponds to KML's IconStyle object.
927
+ class IconStyle < ColorStyle
928
+ attr_accessor :scale, :heading, :hotspot, :icon
875
929
 
876
- def initialize(href, scale = 1, heading = 0, hs_x = 0.5, hs_y = 0.5, hs_xunits = :fraction, hs_yunits = :fraction, color = 'ffffffff', colormode = :normal)
877
- super(color, colormode)
878
- @scale = scale
879
- @heading = heading
880
- @icon = Icon.new(href) unless href.nil?
881
- @hotspot = KMLxy.new(hs_x, hs_y, hs_xunits, hs_yunits) unless (hs_x.nil? and hs_y.nil? and hs_xunits.nil? and hs_yunits.nil?)
882
- end
930
+ def initialize(href, scale = 1, heading = 0, hs_x = 0.5, hs_y = 0.5, hs_xunits = :fraction, hs_yunits = :fraction, color = 'ffffffff', colormode = :normal)
931
+ super(color, colormode)
932
+ @scale = scale
933
+ @heading = heading
934
+ @icon = Icon.new(href) unless href.nil?
935
+ @hotspot = XY.new(hs_x, hs_y, hs_xunits, hs_yunits) unless (hs_x.nil? and hs_y.nil? and hs_xunits.nil? and hs_yunits.nil?)
936
+ end
883
937
 
884
- def to_kml(indent = 0)
885
- k = <<-iconstyle1
886
- #{ ' ' * indent }<IconStyle id="#{@id}">
887
- #{ super(indent + 4) }
888
- iconstyle1
889
- k << "#{ ' ' * indent } <scale>#{@scale}</scale>\n" unless @scale.nil?
890
- k << "#{ ' ' * indent } <heading>#{@heading}</heading>\n" unless @heading.nil?
891
- k << @icon.to_kml(indent + 4) unless @icon.nil?
892
- k << "#{ ' ' * indent } <hotSpot x=\"#{@hotspot.x}\" y=\"#{@hotspot.y}\" xunits=\"#{@hotspot.xunits}\" yunits=\"#{@hotspot.yunits}\" />\n" unless @hotspot.nil?
893
- k << "#{ ' ' * indent }</IconStyle>\n"
938
+ def to_kml(elem = nil)
939
+ k = REXML::Element.new 'IconStyle'
940
+ super(k)
941
+ Kamelopard.kml_array( k, [
942
+ [ @scale, 'scale' ],
943
+ [ @heading, 'heading' ]
944
+ ])
945
+ if not @hotspot.nil? then
946
+ h = REXML::Element.new 'hotSpot'
947
+ h.attributes['x'] = @hotspot.x
948
+ h.attributes['y'] = @hotspot.y
949
+ h.attributes['xunits'] = @hotspot.xunits
950
+ h.attributes['yunits'] = @hotspot.yunits
951
+ k.elements << h
952
+ end
953
+ @icon.to_kml(k) unless @icon.nil?
954
+ elem.elements << k unless elem.nil?
955
+ k
956
+ end
894
957
  end
895
- end
896
958
 
897
- # Corresponds to KML's LabelStyle object
898
- class LabelStyle < ColorStyle
899
- attr_accessor :scale
959
+ # Corresponds to KML's LabelStyle object
960
+ class LabelStyle < ColorStyle
961
+ attr_accessor :scale
900
962
 
901
- def initialize(scale = 1, color = 'ffffffff', colormode = :normal)
902
- super(color, colormode)
903
- @scale = scale
904
- end
905
-
906
- def to_kml(indent = 0)
963
+ def initialize(scale = 1, color = 'ffffffff', colormode = :normal)
964
+ super(color, colormode)
965
+ @scale = scale
966
+ end
907
967
 
908
- <<-labelstyle
909
- #{ ' ' * indent }<LabelStyle id="#{@id}">
910
- #{ super(indent + 4) }
911
- #{ ' ' * indent } <scale>#{@scale}</scale>
912
- #{ ' ' * indent }</LabelStyle>
913
- labelstyle
968
+ def to_kml(elem = nil)
969
+ k = REXML::Element.new 'LabelStyle'
970
+ super k
971
+ s = REXML::Element.new 'scale'
972
+ s.text = @scale
973
+ k.elements << s
974
+ elem.elements << k unless elem.nil?
975
+ k
976
+ end
914
977
  end
915
- end
916
978
 
917
- # Corresponds to KML's LineStyle object. Color is stored as an 8-character hex
918
- # string, with two characters each of alpha, blue, green, and red values, in
919
- # that order, matching the ordering the KML spec demands.
920
- class LineStyle < ColorStyle
921
- attr_accessor :outercolor, :outerwidth, :physicalwidth, :width
922
-
923
- def initialize(width = 1, outercolor = 'ffffffff', outerwidth = 0, physicalwidth = 0, color = 'ffffffff', colormode = :normal)
924
- super(color, colormode)
925
- @width = width
926
- @outercolor = outercolor
927
- @outerwidth = outerwidth
928
- @physicalwidth = physicalwidth
929
- end
979
+ # Corresponds to KML's LineStyle object. Color is stored as an 8-character hex
980
+ # string, with two characters each of alpha, blue, green, and red values, in
981
+ # that order, matching the ordering the KML spec demands.
982
+ class LineStyle < ColorStyle
983
+ attr_accessor :outerColor, :outerWidth, :physicalWidth, :width
930
984
 
931
- def to_kml(indent = 0)
932
-
933
- <<-linestyle
934
- #{ ' ' * indent }<LineStyle id="#{@id}">
935
- #{ super(indent + 4) }
936
- #{ ' ' * indent } <width>#{@width}</width>
937
- #{ ' ' * indent } <gx:outerColor>#{@outercolor}</gx:outerColor>
938
- #{ ' ' * indent } <gx:outerWidth>#{@outerwidth}</gx:outerWidth>
939
- #{ ' ' * indent } <gx:physicalWidth>#{@physicalwidth}</gx:physicalWidth>
940
- #{ ' ' * indent }</LineStyle>
941
- linestyle
942
- end
943
- end
985
+ def initialize(width = 1, outercolor = 'ffffffff', outerwidth = 0, physicalwidth = 0, color = 'ffffffff', colormode = :normal)
986
+ super(color, colormode)
987
+ @width = width
988
+ @outerColor = outercolor
989
+ @outerWidth = outerwidth
990
+ @physicalWidth = physicalwidth
991
+ end
944
992
 
945
- # Corresponds to KML's ListStyle object. Color is stored as an 8-character hex
946
- # string, with two characters each of alpha, blue, green, and red values, in
947
- # that order, matching the ordering the KML spec demands.
948
- class ListStyle < ColorStyle
949
- attr_accessor :listitemtype, :bgcolor, :state, :href
950
-
951
- def initialize(bgcolor = nil, state = nil, href = nil, listitemtype = nil)
952
- super(nil, :normal)
953
- @bgcolor = bgcolor
954
- @state = state
955
- @href = href
956
- @listitemtype = listitemtype
993
+ def to_kml(elem = nil)
994
+ k = REXML::Element.new 'LineStyle'
995
+ super k
996
+ Kamelopard.kml_array(k, [
997
+ [ @width, 'width' ],
998
+ [ @outerColor, 'gx:outerColor' ],
999
+ [ @outerWidth, 'gx:outerWidth' ],
1000
+ [ @physicalWidth, 'gx:physicalWidth' ],
1001
+ ])
1002
+ elem.elements << k unless elem.nil?
1003
+ k
1004
+ end
957
1005
  end
958
1006
 
959
- def to_kml(indent = 0)
960
- k = "#{ ' ' * indent }<ListStyle id=\"#{@id}\">\n"
961
- k << kml_array([
962
- [@listitemtype, 'listItemType', true],
963
- [@bgcolor, 'bgColor', true]
964
- ], indent + 4)
965
- if (! @state.nil? or ! @href.nil?) then
966
- k << "#{ ' ' * indent } <ItemIcon>\n"
967
- k << "#{ ' ' * indent } <state>#{@state}</state>\n" unless @state.nil?
968
- k << "#{ ' ' * indent } <href>#{@href}</href>\n" unless @href.nil?
969
- k << "#{ ' ' * indent } </ItemIcon>\n"
970
- end
971
- k << "#{ ' ' * indent }</ListStyle>\n"
972
- k
973
- end
974
- end
1007
+ # Corresponds to KML's ListStyle object. Color is stored as an 8-character hex
1008
+ # string, with two characters each of alpha, blue, green, and red values, in
1009
+ # that order, matching the ordering the KML spec demands.
1010
+ class ListStyle < ColorStyle
1011
+ attr_accessor :listItemType, :bgColor, :state, :href
975
1012
 
976
- # Corresponds to KML's PolyStyle object. Color is stored as an 8-character hex
977
- # string, with two characters each of alpha, blue, green, and red values, in
978
- # that order, matching the ordering the KML spec demands.
979
- class PolyStyle < ColorStyle
980
- attr_accessor :fill, :outline
1013
+ def initialize(bgcolor = nil, state = nil, href = nil, listitemtype = nil)
1014
+ super(nil, :normal)
1015
+ @bgcolor = bgcolor
1016
+ @state = state
1017
+ @href = href
1018
+ @listitemtype = listitemtype
1019
+ end
981
1020
 
982
- def initialize(fill = 1, outline = 1, color = 'ffffffff', colormode = :normal)
983
- super(color, colormode)
984
- @fill = fill
985
- @outline = outline
1021
+ def to_kml(elem = nil)
1022
+ k = REXML::Element.new 'ListStyle'
1023
+ super k
1024
+ Kamelopard.kml_array(k, [
1025
+ [@listitemtype, 'listItemType'],
1026
+ [@bgcolor, 'bgColor']
1027
+ ])
1028
+ if (! @state.nil? or ! @href.nil?) then
1029
+ i = REXML::Element.new 'ItemIcon'
1030
+ Kamelopard.kml_array(i, [
1031
+ [ @state, 'state' ],
1032
+ [ @href, 'href' ]
1033
+ ])
1034
+ k.elements << i
1035
+ end
1036
+ elem.elements << k unless elem.nil?
1037
+ k
1038
+ end
986
1039
  end
987
1040
 
988
- def to_kml(indent = 0)
1041
+ # Corresponds to KML's PolyStyle object. Color is stored as an 8-character hex
1042
+ # string, with two characters each of alpha, blue, green, and red values, in
1043
+ # that order, matching the ordering the KML spec demands.
1044
+ class PolyStyle < ColorStyle
1045
+ attr_accessor :fill, :outline
989
1046
 
990
- k = <<-polystyle
991
- #{ ' ' * indent }<PolyStyle id="#{@id}">
992
- #{ super(indent + 4) }
993
- #{ ' ' * indent } <fill>#{@fill}</fill>
994
- polystyle
995
- k << "#{ ' ' * indent } <outline>#{@outline}</outline>\n" unless @outline.nil?
996
- k << "#{ ' ' * indent }</PolyStyle>\n"
997
- k
998
- end
999
- end
1047
+ def initialize(fill = 1, outline = 1, color = 'ffffffff', colormode = :normal)
1048
+ super(color, colormode)
1049
+ @fill = fill
1050
+ @outline = outline
1051
+ end
1000
1052
 
1001
- # Abstract class corresponding to KML's StyleSelector object.
1002
- class StyleSelector < KMLObject
1003
- attr_accessor :attached
1004
- def initialize
1005
- super
1006
- @attached = false
1007
- Document.instance.styles << self
1053
+ def to_kml(elem = nil)
1054
+ k = REXML::Element.new 'PolyStyle'
1055
+ super k
1056
+ Kamelopard.kml_array( k, [
1057
+ [ @fill, 'fill' ],
1058
+ [ @outline, 'outline' ]
1059
+ ])
1060
+ elem.elements << k unless elem.nil?
1061
+ k
1062
+ end
1008
1063
  end
1009
1064
 
1010
- def attached?
1011
- @attached
1012
- end
1065
+ # Abstract class corresponding to KML's StyleSelector object.
1066
+ class StyleSelector < Object
1067
+ attr_accessor :attached
1068
+ def initialize
1069
+ super
1070
+ @attached = false
1071
+ Document.instance.styles << self
1072
+ end
1013
1073
 
1014
- def attach(obj)
1015
- @attached = true
1016
- obj.styles << self
1017
- end
1018
- end
1074
+ def attached?
1075
+ @attached
1076
+ end
1019
1077
 
1020
- # Corresponds to KML's Style object. Attributes are expected to be IconStyle,
1021
- # LabelStyle, LineStyle, PolyStyle, BalloonStyle, and ListStyle objects.
1022
- class Style < StyleSelector
1023
- attr_accessor :icon, :label, :line, :poly, :balloon, :list
1024
- def initialize(icon = nil, label = nil, line = nil, poly = nil, balloon = nil, list = nil)
1025
- super()
1026
- @icon = icon
1027
- @label = label
1028
- @line = line
1029
- @poly = poly
1030
- @balloon = balloon
1031
- @list = list
1032
- end
1078
+ def attach(obj)
1079
+ @attached = true
1080
+ obj.styles << self
1081
+ end
1033
1082
 
1034
- def to_kml(indent = 0)
1035
- k = ''
1036
- k << super + "#{ ' ' * indent }<Style id=\"#{@id}\">\n"
1037
- k << @icon.to_kml(indent + 4) unless @icon.nil?
1038
- k << @label.to_kml(indent + 4) unless @label.nil?
1039
- k << @line.to_kml(indent + 4) unless @line.nil?
1040
- k << @poly.to_kml(indent + 4) unless @poly.nil?
1041
- k << @balloon.to_kml(indent + 4) unless @balloon.nil?
1042
- k << @list.to_kml(indent + 4) unless @list.nil?
1043
- k << "#{ ' ' * indent }</Style>\n"
1044
- k
1083
+ def to_kml(elem = nil)
1084
+ elem = REXML::Element.new 'StyleSelector' if elem.nil?
1085
+ super elem
1086
+ elem
1087
+ end
1045
1088
  end
1046
- end
1047
1089
 
1048
- # Corresponds to KML's StyleMap object.
1049
- class StyleMap < StyleSelector
1050
- # StyleMap manages pairs. The first entry in each pair is a string key, the
1051
- # second is either a Style or a styleUrl. It will be assumed to be the
1052
- # latter if its kind_of? method doesn't claim it's a Style object
1053
- def initialize(pairs = {})
1054
- super()
1055
- @pairs = pairs
1056
- end
1090
+ # Corresponds to KML's Style object. Attributes are expected to be IconStyle,
1091
+ # LabelStyle, LineStyle, PolyStyle, BalloonStyle, and ListStyle objects.
1092
+ class Style < StyleSelector
1093
+ attr_accessor :icon, :label, :line, :poly, :balloon, :list
1094
+ def initialize(icon = nil, label = nil, line = nil, poly = nil, balloon = nil, list = nil)
1095
+ super()
1096
+ @icon = icon
1097
+ @label = label
1098
+ @line = line
1099
+ @poly = poly
1100
+ @balloon = balloon
1101
+ @list = list
1102
+ end
1057
1103
 
1058
- # Adds a new Style to the StyleMap.
1059
- def merge(a)
1060
- @pairs.merge(a)
1104
+ def to_kml(elem = nil)
1105
+ k = REXML::Element.new 'Style'
1106
+ super(k)
1107
+ @icon.to_kml(k) unless @icon.nil?
1108
+ @label.to_kml(k) unless @label.nil?
1109
+ @line.to_kml(k) unless @line.nil?
1110
+ @poly.to_kml(k) unless @poly.nil?
1111
+ @balloon.to_kml(k) unless @balloon.nil?
1112
+ @list.to_kml(k) unless @list.nil?
1113
+ elem.elements << k unless elem.nil?
1114
+ k
1115
+ end
1061
1116
  end
1062
1117
 
1063
- def to_kml(indent = 0)
1064
- t = super + "#{ ' ' * indent }<StyleMap id=\"#{@id}\">\n"
1065
- @pairs.each do |k, v|
1066
- t << "#{ ' ' * indent } <Pair>\n"
1067
- t << "#{ ' ' * indent } <key>#{ k }</key>\n"
1068
- if v.kind_of? Style then
1069
- t << ( ' ' * indent ) << v.to_kml(indent + 8)
1070
- else
1071
- t << "#{ ' ' * indent } <styleUrl>#{ v }</styleUrl>\n"
1118
+ # Corresponds to KML's StyleMap object.
1119
+ class StyleMap < StyleSelector
1120
+ # StyleMap manages pairs. The first entry in each pair is a string key, the
1121
+ # second is either a Style or a styleUrl. It will be assumed to be the
1122
+ # latter if its kind_of? method doesn't claim it's a Style object
1123
+ def initialize(pairs = {})
1124
+ super()
1125
+ @pairs = pairs
1126
+ end
1127
+
1128
+ # Adds a new Style to the StyleMap.
1129
+ def merge(a)
1130
+ @pairs.merge!(a)
1131
+ end
1132
+
1133
+ def to_kml(elem = nil)
1134
+ t = REXML::Element.new 'StyleMap'
1135
+ super t
1136
+ @pairs.each do |k, v|
1137
+ p = REXML::Element.new 'Pair'
1138
+ key = REXML::Element.new 'key'
1139
+ key.text = k
1140
+ p.elements << key
1141
+ if v.kind_of? Style then
1142
+ v.to_kml(p)
1143
+ else
1144
+ s = REXML::Element.new 'styleUrl'
1145
+ s.text = v
1146
+ p.elements << s
1147
+ end
1148
+ t.elements << p
1072
1149
  end
1073
- t << "#{ ' ' * indent } </Pair>\n"
1150
+ elem.elements << t unless elem.nil?
1151
+ t
1074
1152
  end
1075
- t << "#{ ' ' * indent }</StyleMap>\n"
1076
- t
1077
1153
  end
1078
- end
1079
1154
 
1080
- # Corresponds to KML's Placemark objects. The geometry attribute requires a
1081
- # descendant of Geometry
1082
- class Placemark < Feature
1083
- attr_accessor :name, :geometry
1084
- def initialize(name = nil, geo = nil)
1085
- super(name)
1086
- Document.instance.folder << self
1087
- if geo.respond_to? '[]' then
1088
- @geometry = geo
1089
- else
1090
- @geometry = [ geo ]
1155
+ # Corresponds to KML's Placemark objects. The geometry attribute requires a
1156
+ # descendant of Geometry
1157
+ class Placemark < Feature
1158
+ attr_accessor :name, :geometry
1159
+ def initialize(name = nil, geo = nil)
1160
+ super(name)
1161
+ if geo.respond_to? '[]' then
1162
+ @geometry = geo
1163
+ else
1164
+ @geometry = [ geo ]
1165
+ end
1091
1166
  end
1092
- end
1093
-
1094
- def to_kml(indent = 0)
1095
- a = "#{ ' ' * indent }<Placemark id=\"#{ @id }\">\n"
1096
- a << super(indent + 4) {
1097
- k = ''
1098
- @geometry.each do |i| k << i.to_kml(indent + 4) unless i.nil? end
1167
+
1168
+ def to_kml(elem = nil)
1169
+ k = REXML::Element.new 'Placemark'
1170
+ super k
1171
+ @geometry.each do |i| i.to_kml(k) unless i.nil? end
1172
+ elem << k unless elem.nil?
1099
1173
  k
1100
- }
1101
- a << "#{ ' ' * indent }</Placemark>\n"
1102
- end
1103
-
1104
- def to_s
1105
- "Placemark id #{ @id } named #{ @name }"
1106
- end
1174
+ end
1107
1175
 
1108
- def longitude
1109
- @geometry.longitude
1110
- end
1176
+ def to_s
1177
+ "Placemark id #{ @id } named #{ @name }"
1178
+ end
1111
1179
 
1112
- def latitude
1113
- @geometry.latitude
1114
- end
1180
+ def longitude
1181
+ @geometry.longitude
1182
+ end
1115
1183
 
1116
- def altitude
1117
- @geometry.altitude
1118
- end
1184
+ def latitude
1185
+ @geometry.latitude
1186
+ end
1119
1187
 
1120
- def altitudeMode
1121
- @geometry.altitudeMode
1122
- end
1188
+ def altitude
1189
+ @geometry.altitude
1190
+ end
1123
1191
 
1124
- def point
1125
- if @geometry[0].kind_of? KMLPoint then
1126
- @geometry[0]
1127
- else
1128
- raise "This placemark uses a non-point geometry, but the operation you're trying requires a point object"
1192
+ def altitudeMode
1193
+ @geometry.altitudeMode
1129
1194
  end
1130
- end
1131
- end
1132
1195
 
1133
- # Abstract class corresponding to KML's gx:TourPrimitive object. Tours are made up
1134
- # of descendants of these.
1135
- class TourPrimitive < KMLObject
1136
- def initialize
1137
- Document.instance.tour << self
1196
+ def point
1197
+ if @geometry[0].kind_of? Point then
1198
+ @geometry[0]
1199
+ else
1200
+ raise "This placemark uses a non-point geometry, but the operation you're trying requires a point object"
1201
+ end
1202
+ end
1138
1203
  end
1139
- end
1140
1204
 
1141
- # Cooresponds to KML's gx:FlyTo object. The @view parameter needs to look like an
1142
- # AbstractView object
1143
- class FlyTo < TourPrimitive
1144
- attr_accessor :duration, :mode, :view
1145
-
1146
- def initialize(view = nil, range = nil, duration = 0, mode = :bounce)
1147
- @duration = duration
1148
- @mode = mode
1149
- if view.kind_of? AbstractView then
1150
- @view = view
1151
- else
1152
- @view = LookAt.new(view)
1205
+ # Abstract class corresponding to KML's gx:TourPrimitive object. Tours are made up
1206
+ # of descendants of these.
1207
+ class TourPrimitive < Object
1208
+ def initialize
1209
+ Document.instance.tour << self
1210
+ super
1153
1211
  end
1154
- if view.respond_to? 'range' and not range.nil? then
1155
- @view.range = range
1156
- end
1157
- super()
1158
1212
  end
1159
1213
 
1160
- def to_kml(indent = 0)
1161
- k = super + "#{ ' ' * indent }<gx:FlyTo>\n"
1162
- k << kml_array([
1163
- [ @duration, 'gx:duration', true ],
1164
- [ @mode, 'gx:flyToMode', true ]
1165
- ], indent + 4)
1166
- k << @view.to_kml(indent + 4) unless @view.nil?
1167
- k << "#{ ' ' * indent }</gx:FlyTo>\n"
1168
- end
1169
- end
1214
+ # Cooresponds to KML's gx:FlyTo object. The @view parameter needs to look like an
1215
+ # AbstractView object
1216
+ class FlyTo < TourPrimitive
1217
+ attr_accessor :duration, :mode, :view
1170
1218
 
1171
- # Corresponds to KML's gx:AnimatedUpdate object. For now at least, this isn't very
1172
- # intelligent; you've got to manually craft the <Change> tag(s) within the
1173
- # object.
1174
- class AnimatedUpdate < TourPrimitive
1175
- # For now, the user has to specify the change / create / delete elements in
1176
- # the <Update> manually, rather than creating objects.
1177
- attr_accessor :target, :delayedstart, :updates, :duration
1178
-
1179
- # The updates argument is an array of strings containing <Change> elements
1180
- def initialize(updates = [], duration = 0, target = '', delayedstart = nil)
1181
- super()
1182
- begin
1183
- raise "incorrect object type" unless @target.kind_of? KMLObject
1184
- @target = target.id
1185
- rescue RuntimeError
1186
- @target = target
1187
- end
1188
- @updates = updates
1189
- @duration = duration
1190
- @delayedstart = delayedstart
1191
- end
1219
+ def initialize(view = nil, range = nil, duration = 0, mode = :bounce)
1220
+ @duration = duration
1221
+ @mode = mode
1222
+ if view.kind_of? AbstractView then
1223
+ @view = view
1224
+ else
1225
+ @view = LookAt.new(view)
1226
+ end
1227
+ if view.respond_to? 'range' and not range.nil? then
1228
+ @view.range = range
1229
+ end
1230
+ super()
1231
+ end
1192
1232
 
1193
- # Adds another update string, presumably containing a <Change> element
1194
- def <<(a)
1195
- @updates << a << "\n"
1233
+ def to_kml(elem = nil)
1234
+ k = REXML::Element.new 'gx:FlyTo'
1235
+ super k
1236
+ Kamelopard.kml_array(k, [
1237
+ [ @duration, 'gx:duration' ],
1238
+ [ @mode, 'gx:flyToMode' ]
1239
+ ])
1240
+ @view.to_kml k unless @view.nil?
1241
+ elem << k unless elem.nil?
1242
+ k
1243
+ end
1196
1244
  end
1197
1245
 
1198
- def to_kml(indent = 0)
1199
- k = super + <<-animatedupdate_kml
1200
- #{ ' ' * indent }<gx:AnimatedUpdate>
1201
- #{ ' ' * indent } <gx:duration>#{@duration}</gx:duration>
1202
- animatedupdate_kml
1203
- k << "#{ ' ' * indent } <gx:delayeStart>#{@delayedstart}</gx:delayedStart>\n" unless @delayedstart.nil?
1204
- k << "#{ ' ' * indent } <Update>\n"
1205
- k << "#{ ' ' * indent } <targetHref>#{@target}</targetHref>\n"
1206
- k << "#{ ' ' * indent } " << @updates.join("\n#{ ' ' * (indent + 1) }")
1207
- k << "#{ ' ' * indent } </Update>\n#{ ' ' * indent }</gx:AnimatedUpdate>\n"
1208
- k
1209
- end
1210
- end
1246
+ # Corresponds to KML's gx:AnimatedUpdate object. For now at least, this isn't very
1247
+ # intelligent; you've got to manually craft the <Change> tag(s) within the
1248
+ # object.
1249
+ class AnimatedUpdate < TourPrimitive
1250
+ # XXX For now, the user has to specify the change / create / delete elements in
1251
+ # the <Update> manually, rather than creating objects.
1252
+ attr_accessor :target, :delayedStart, :updates, :duration
1253
+
1254
+ # The updates argument is an array of strings containing <Change> elements
1255
+ def initialize(updates = [], duration = 0, target = '', delayedstart = nil)
1256
+ super()
1257
+ begin
1258
+ raise "incorrect object type" unless @target.kind_of? Object
1259
+ @target = target.id
1260
+ rescue RuntimeError
1261
+ @target = target
1262
+ end
1263
+ @updates = updates
1264
+ @duration = duration
1265
+ @delayedStart = delayedstart
1266
+ end
1211
1267
 
1212
- # Corresponds to a KML gx:TourControl object
1213
- class TourControl < TourPrimitive
1214
- def initialize
1215
- super
1216
- end
1268
+ # Adds another update string, presumably containing a <Change> element
1269
+ def <<(a)
1270
+ @updates << REXML::Document.new(a).root
1271
+ end
1217
1272
 
1218
- def to_kml(indent = 0)
1219
- k = "#{ ' ' * indent }<gx:TourControl id=\"#{ @id }\">\n"
1220
- k << "#{ ' ' * indent } <gx:playMode>pause</gx:playMode>\n"
1221
- k << "#{ ' ' * indent }</gx:TourControl>\n"
1273
+ def to_kml(elem = nil)
1274
+ k = REXML::Element.new 'gx:AnimatedUpdate'
1275
+ super(k)
1276
+ d = REXML::Element.new 'gx:duration'
1277
+ d.text = @duration
1278
+ k << d
1279
+ if not @delayedStart.nil? then
1280
+ d = REXML::Element.new 'gx:delayedStart'
1281
+ d.text = @delayedStart
1282
+ k << d
1283
+ end
1284
+ d = REXML::Element.new 'Update'
1285
+ q = REXML::Element.new 'targetHref'
1286
+ q.text = @target
1287
+ d << q
1288
+ @updates.each do |i| d << i end
1289
+ k << d
1290
+ elem << k unless elem.nil?
1291
+ k
1292
+ end
1222
1293
  end
1223
- end
1224
1294
 
1225
- # Corresponds to a KML gx:Wait object
1226
- class Wait < TourPrimitive
1227
- attr_accessor :duration
1228
- def initialize(duration = 0)
1229
- super()
1230
- @duration = duration
1231
- end
1295
+ # Corresponds to a KML gx:TourControl object
1296
+ class TourControl < TourPrimitive
1297
+ def initialize
1298
+ super
1299
+ end
1232
1300
 
1233
- def to_kml(indent = 0)
1234
- super + <<-wait_kml
1235
- #{ ' ' * indent }<gx:Wait><gx:duration>#{@duration}</gx:duration></gx:Wait>
1236
- wait_kml
1301
+ def to_kml(elem = nil)
1302
+ k = REXML::Element.new 'gx:TourControl'
1303
+ super(k)
1304
+ q = REXML::Element.new 'gx:playMode'
1305
+ q.text = 'pause'
1306
+ k << q
1307
+ elem << k unless elem.nil?
1308
+ k
1309
+ end
1237
1310
  end
1238
- end
1239
1311
 
1240
- # Corresponds to a KML gx:SoundCue object
1241
- class SoundCue < TourPrimitive
1242
- attr_accessor :href, :delayedStart
1243
- def initialize(href, delayedStart = nil)
1244
- super()
1245
- @href = href
1246
- @delayedStart = delayedStart
1247
- end
1312
+ # Corresponds to a KML gx:Wait object
1313
+ class Wait < TourPrimitive
1314
+ attr_accessor :duration
1315
+ def initialize(duration = 0)
1316
+ super()
1317
+ @duration = duration
1318
+ end
1248
1319
 
1249
- def to_kml(indent = 0)
1250
- k = "#{ ' ' * indent }<gx:SoundCue id=\"#{ @id }\">\n"
1251
- k << "#{ ' ' * indent } <href>#{ @href }</href>\n"
1252
- k << "#{ ' ' * indent } <gx:delayedStart>#{ @delayedStart }</gx:delayedStart>\n" unless @delayedStart.nil?
1253
- k << "#{ ' ' * indent}</gx:SoundCue>\n"
1320
+ def to_kml(elem = nil)
1321
+ k = REXML::Element.new 'gx:Wait'
1322
+ super k
1323
+ d = REXML::Element.new 'gx:duration'
1324
+ d.text = @duration
1325
+ k << d
1326
+ elem << k unless elem.nil?
1327
+ k
1328
+ end
1254
1329
  end
1255
- end
1256
1330
 
1257
- # Corresponds to a KML gx:Tour object
1258
- class Tour < KMLObject
1259
- attr_accessor :name, :description, :last_abs_view
1260
- def initialize(name = nil, description = nil)
1261
- super()
1262
- @name = name
1263
- @description = description
1264
- @items = []
1265
- end
1331
+ # Corresponds to a KML gx:SoundCue object
1332
+ class SoundCue < TourPrimitive
1333
+ attr_accessor :href, :delayedStart
1334
+ def initialize(href, delayedStart = nil)
1335
+ super()
1336
+ @href = href
1337
+ @delayedStart = delayedStart
1338
+ end
1266
1339
 
1267
- # Add another element to this Tour
1268
- def <<(a)
1269
- @items << a
1270
- @last_abs_view = a.view if a.kind_of? FlyTo
1340
+ def to_kml(elem = nil)
1341
+ k = REXML::Element.new 'gx:SoundCue'
1342
+ super k
1343
+ d = REXML::Element.new 'href'
1344
+ d.text = @href
1345
+ k << d
1346
+ if not @delayedStart.nil? then
1347
+ d = REXML::Element.new 'gx:delayedStart'
1348
+ d.text = @delayedStart
1349
+ k << d
1350
+ end
1351
+ elem << k unless elem.nil?
1352
+ k
1353
+ end
1271
1354
  end
1272
1355
 
1273
- def to_kml(indent = 0)
1274
- k = super + "#{ ' ' * indent }<gx:Tour id=\"#{ @id }\">\n"
1275
- k << kml_array([
1276
- [ @name, 'name', true ],
1277
- [ @description, 'description', true ],
1278
- ], indent + 4)
1279
- k << "#{ ' ' * indent } <gx:Playlist>\n";
1356
+ # Corresponds to a KML gx:Tour object
1357
+ class Tour < Object
1358
+ attr_accessor :name, :description, :last_abs_view
1359
+ def initialize(name = nil, description = nil)
1360
+ super()
1361
+ @name = name
1362
+ @description = description
1363
+ @items = []
1364
+ Document.instance.tours << self
1365
+ end
1280
1366
 
1281
- @items.map do |a| k << a.to_kml(indent + 8) << "\n" end
1367
+ # Add another element to this Tour
1368
+ def <<(a)
1369
+ @items << a
1370
+ @last_abs_view = a.view if a.kind_of? FlyTo
1371
+ end
1282
1372
 
1283
- k << "#{ ' ' * indent } </gx:Playlist>\n"
1284
- k << "#{ ' ' * indent }</gx:Tour>\n"
1285
- k
1373
+ def to_kml(elem = nil)
1374
+ k = REXML::Element.new 'gx:Tour'
1375
+ super k
1376
+ Kamelopard.kml_array(k, [
1377
+ [ @name, 'name' ],
1378
+ [ @description, 'description' ],
1379
+ ])
1380
+ p = REXML::Element.new 'gx:Playlist'
1381
+ @items.map do |a| a.to_kml p end
1382
+ k << p
1383
+ elem << k unless elem.nil?
1384
+ k
1385
+ end
1286
1386
  end
1287
- end
1288
1387
 
1289
- # Abstract class corresponding to the KML Overlay object
1290
- class Overlay < Feature
1291
- attr_accessor :color, :drawOrder, :icon
1388
+ # Abstract class corresponding to the KML Overlay object
1389
+ class Overlay < Feature
1390
+ attr_accessor :color, :drawOrder, :icon
1292
1391
 
1293
- def initialize(icon, name = nil)
1294
- super(name)
1295
- if icon.respond_to?('to_kml') then
1296
- @icon = icon
1297
- elsif not icon.nil?
1298
- @icon = Icon.new(icon.to_s)
1392
+ def initialize(icon, name = nil)
1393
+ super(name)
1394
+ Document.instance.folder << self
1395
+ if icon.respond_to?('to_kml') then
1396
+ @icon = icon
1397
+ elsif not icon.nil?
1398
+ @icon = Icon.new(icon.to_s)
1399
+ end
1299
1400
  end
1300
- Document.instance.folder << self
1301
- end
1302
1401
 
1303
- def to_kml(indent = 0)
1304
- k = super(indent) + kml_array([
1305
- [ @color, 'color', true ],
1306
- [ @drawOrder, 'drawOrder', true ],
1307
- ], indent + 4)
1308
- k << @icon.to_kml(indent) unless @icon.nil?
1309
- k
1402
+ def to_kml(elem)
1403
+ super
1404
+ Kamelopard.kml_array(elem, [
1405
+ [ @color, 'color' ],
1406
+ [ @drawOrder, 'drawOrder' ],
1407
+ ])
1408
+ @icon.to_kml(elem) unless @icon.nil?
1409
+ elem
1410
+ end
1310
1411
  end
1311
- end
1312
1412
 
1313
- # Corresponds to KML's ScreenOverlay object
1314
- class ScreenOverlay < Overlay
1315
- attr_accessor :overlayXY, :screenXY, :rotationXY, :size, :rotation
1316
- def initialize(icon, name = nil, size = nil, rotation = nil, overlayXY = nil, screenXY = nil, rotationXY = nil)
1317
- super(icon, name)
1318
- @overlayXY = overlayXY
1319
- @screenXY = screenXY
1320
- @rotationXY = rotationXY
1321
- @size = size
1322
- @rotation = rotation
1323
- end
1413
+ # Corresponds to KML's ScreenOverlay object
1414
+ class ScreenOverlay < Overlay
1415
+ attr_accessor :overlayXY, :screenXY, :rotationXY, :size, :rotation
1416
+ def initialize(icon, name = nil, size = nil, rotation = nil, overlayXY = nil, screenXY = nil, rotationXY = nil)
1417
+ super(icon, name)
1418
+ @overlayXY = overlayXY
1419
+ @screenXY = screenXY
1420
+ @rotationXY = rotationXY
1421
+ @size = size
1422
+ @rotation = rotation
1423
+ end
1324
1424
 
1325
- def to_kml(indent = 0)
1326
- k = "#{ ' ' * indent }<ScreenOverlay id=\"#{ @id }\">\n"
1327
- k << super(indent + 4)
1328
- k << @overlayXY.to_kml('overlayXY', indent + 4) unless @overlayXY.nil?
1329
- k << @screenXY.to_kml('screenXY', indent + 4) unless @screenXY.nil?
1330
- k << @rotationXY.to_kml('rotationXY', indent + 4) unless @rotationXY.nil?
1331
- k << @size.to_kml('size', indent + 4) unless @size.nil?
1332
- k << "#{ ' ' * indent } <rotation>#{ @rotation }</rotation>\n" unless @rotation.nil?
1333
- k << "#{ ' ' * indent }</ScreenOverlay>\n"
1425
+ def to_kml(elem = nil)
1426
+ k = REXML::Element.new 'ScreenOverlay'
1427
+ super k
1428
+ @overlayXY.to_kml('overlayXY', k) unless @overlayXY.nil?
1429
+ @screenXY.to_kml('screenXY', k) unless @screenXY.nil?
1430
+ @rotationXY.to_kml('rotationXY', k) unless @rotationXY.nil?
1431
+ @size.to_kml('size', k) unless @size.nil?
1432
+ if ! @rotation.nil? then
1433
+ d = REXML::Element.new 'rotation'
1434
+ d.text = @rotation
1435
+ k << d
1436
+ end
1437
+ elem << k unless elem.nil?
1438
+ k
1439
+ end
1334
1440
  end
1335
- end
1336
1441
 
1337
- # Supporting object for the PhotoOverlay class
1338
- class ViewVolume
1339
- attr_accessor :leftFov, :rightFov, :bottomFov, :topFov, :near
1340
- def initialize(near, leftFov = -45, rightFov = 45, bottomFov = -45, topFov = 45)
1341
- @leftFov = leftFov
1342
- @rightFov = rightFov
1343
- @bottomFov = bottomFov
1344
- @topFov = topFov
1345
- @near = near
1346
- end
1442
+ # Supporting object for the PhotoOverlay class
1443
+ class ViewVolume
1444
+ attr_accessor :leftFov, :rightFov, :bottomFov, :topFov, :near
1445
+ def initialize(near, leftFov = -45, rightFov = 45, bottomFov = -45, topFov = 45)
1446
+ @leftFov = leftFov
1447
+ @rightFov = rightFov
1448
+ @bottomFov = bottomFov
1449
+ @topFov = topFov
1450
+ @near = near
1451
+ end
1347
1452
 
1348
- def to_kml(indent = 0)
1349
-
1350
- <<-viewvolume
1351
- #{ ' ' * indent }<ViewVolume>
1352
- #{ ' ' * indent } <near>#{@near}</near>
1353
- #{ ' ' * indent } <leftFov>#{@leftFov}</leftFov>
1354
- #{ ' ' * indent } <rightFov>#{@rightFov}</rightFov>
1355
- #{ ' ' * indent } <bottomFov>#{@bottomFov}</bottomFov>
1356
- #{ ' ' * indent } <topFov>#{@topFov}</topFov>
1357
- #{ ' ' * indent }</ViewVolume>
1358
- viewvolume
1453
+ def to_kml(elem = nil)
1454
+ p = REXML::Element.new 'ViewVolume'
1455
+ {
1456
+ :near => @near,
1457
+ :leftFov => @leftFov,
1458
+ :rightFov => @rightFov,
1459
+ :topFov => @topFov,
1460
+ :bottomFov => @bottomFov
1461
+ }.each do |k, v|
1462
+ d = REXML::Element.new k.to_s
1463
+ d.text = v
1464
+ p << d
1465
+ end
1466
+ elem << p unless elem.nil?
1467
+ p
1468
+ end
1359
1469
  end
1360
- end
1361
1470
 
1362
- # Supporting object for the PhotoOverlay class
1363
- class ImagePyramid
1364
- attr_accessor :tileSize, :maxWidth, :maxHeight, :gridOrigin
1471
+ # Supporting object for the PhotoOverlay class
1472
+ class ImagePyramid
1473
+ attr_accessor :tileSize, :maxWidth, :maxHeight, :gridOrigin
1365
1474
 
1366
- def initialize(maxWidth, maxHeight, gridOrigin, tileSize = 256)
1367
- @tileSize = tileSize
1368
- @maxWidth = maxWidth
1369
- @maxHeight = maxHeight
1370
- @gridOrigin = gridOrigin
1371
- end
1475
+ def initialize(maxWidth, maxHeight, gridOrigin, tileSize = 256)
1476
+ @tileSize = tileSize
1477
+ @maxWidth = maxWidth
1478
+ @maxHeight = maxHeight
1479
+ @gridOrigin = gridOrigin
1480
+ end
1372
1481
 
1373
- def to_kml(indent = 0)
1374
-
1375
- <<-imagepyramid
1376
- #{ ' ' * indent }<ImagePyramid>
1377
- #{ ' ' * indent } <tileSize>#{@tileSize}</tileSize>
1378
- #{ ' ' * indent } <maxWidth>#{@maxWidth}</maxWidth>
1379
- #{ ' ' * indent } <maxHeight>#{@maxHeight}</maxHeight>
1380
- #{ ' ' * indent } <gridOrigin>#{@gridOrigin}</gridOrigin>
1381
- #{ ' ' * indent }</ImagePyramid>
1382
- imagepyramid
1482
+ def to_kml(elem = nil)
1483
+ p = REXML::Element.new 'ImagePyramid'
1484
+ {
1485
+ :tileSize => @tileSize,
1486
+ :maxWidth => @maxWidth,
1487
+ :maxHeight => @maxHeight,
1488
+ :gridOrigin => @gridOrigin
1489
+ }.each do |k, v|
1490
+ d = REXML::Element.new k.to_s
1491
+ d.text = v
1492
+ p << d
1493
+ end
1494
+ elem << p unless elem.nil?
1495
+ p
1496
+ end
1383
1497
  end
1384
- end
1385
1498
 
1386
- # Corresponds to KML's PhotoOverlay class
1387
- class PhotoOverlay < Overlay
1388
- attr_accessor :rotation, :viewvolume, :imagepyramid, :point, :shape
1499
+ # Corresponds to KML's PhotoOverlay class
1500
+ class PhotoOverlay < Overlay
1501
+ attr_accessor :rotation, :viewvolume, :imagepyramid, :point, :shape
1389
1502
 
1390
- def initialize(icon, point, rotation = 0, viewvolume = nil, imagepyramid = nil, shape = :rectangle)
1391
- super(icon)
1392
- if point.respond_to?('point')
1393
- @point = point.point
1394
- else
1395
- @point = point
1503
+ def initialize(icon, point, rotation = 0, viewvolume = nil, imagepyramid = nil, shape = :rectangle)
1504
+ super(icon)
1505
+ if point.respond_to?('point')
1506
+ @point = point.point
1507
+ else
1508
+ @point = point
1509
+ end
1510
+ @rotation = rotation
1511
+ @viewVolume = viewvolume
1512
+ @imagePyramid = imagepyramid
1513
+ @shape = shape
1396
1514
  end
1397
- @rotation = rotation
1398
- @viewVolume = viewvolume
1399
- @imagePyramid = imagepyramid
1400
- @shape = shape
1401
- end
1402
1515
 
1403
- def to_kml(indent = 0)
1404
- k = "#{ ' ' * indent }<PhotoOverlay>\n"
1405
- k << super(indent + 4)
1406
- k << @viewVolume.to_kml(indent + 4) unless @viewVolume.nil?
1407
- k << @imagePyramid.to_kml(indent + 4) unless @imagePyramid.nil?
1408
- k << @point.to_kml(indent + 4, true)
1409
- k << "#{ ' ' * indent } <rotation>#{ @rotation }</rotation>\n"
1410
- k << "#{ ' ' * indent } <shape>#{ @shape }</shape>\n"
1411
- k << "#{ ' ' * indent }</PhotoOverlay>\n"
1516
+ def to_kml(elem = nil)
1517
+ p = REXML::Element.new 'PhotoOverlay'
1518
+ super p
1519
+ @viewVolume.to_kml p unless @viewVolume.nil?
1520
+ @imagePyramid.to_kml p unless @imagePyramid.nil?
1521
+ p << @point.to_kml(true)
1522
+ {
1523
+ :rotation => @rotation,
1524
+ :shape => @shape
1525
+ }.each do |k, v|
1526
+ d = REXML::Element.new k.to_s
1527
+ d.text = v
1528
+ p << d
1529
+ end
1530
+ elem << p unless elem.nil?
1531
+ p
1532
+ end
1412
1533
  end
1413
- end
1414
1534
 
1415
- # Corresponds to KML's LatLonBox and LatLonAltBox
1416
- class LatLonBox
1417
- attr_reader :north, :south, :east, :west
1418
- attr_accessor :rotation, :minAltitude, :maxAltitude, :altitudeMode
1419
-
1420
- def initialize(north, south, east, west, rotation = 0, minAltitude = nil, maxAltitude = nil, altitudeMode = :clampToGround)
1421
- @north = convert_coord north
1422
- @south = convert_coord south
1423
- @east = convert_coord east
1424
- @west = convert_coord west
1425
- @minAltitude = minAltitude
1426
- @maxAltitude = maxAltitude
1427
- @altitudeMode = altitudeMode
1428
- @rotation = rotation
1429
- end
1535
+ # Corresponds to KML's LatLonBox and LatLonAltBox
1536
+ class LatLonBox
1537
+ attr_reader :north, :south, :east, :west
1538
+ attr_accessor :rotation, :minAltitude, :maxAltitude, :altitudeMode
1539
+
1540
+ def initialize(north, south, east, west, rotation = 0, minAltitude = nil, maxAltitude = nil, altitudeMode = :clampToGround)
1541
+ @north = Kamelopard.convert_coord north
1542
+ @south = Kamelopard.convert_coord south
1543
+ @east = Kamelopard.convert_coord east
1544
+ @west = Kamelopard.convert_coord west
1545
+ @minAltitude = minAltitude
1546
+ @maxAltitude = maxAltitude
1547
+ @altitudeMode = altitudeMode
1548
+ @rotation = rotation
1549
+ end
1430
1550
 
1431
- def north=(a)
1432
- @north = convert_coord a
1433
- end
1551
+ def north=(a)
1552
+ @north = Kamelopard.convert_coord a
1553
+ end
1434
1554
 
1435
- def south=(a)
1436
- @south = convert_coord a
1437
- end
1555
+ def south=(a)
1556
+ @south = Kamelopard.convert_coord a
1557
+ end
1438
1558
 
1439
- def east=(a)
1440
- @east = convert_coord a
1441
- end
1559
+ def east=(a)
1560
+ @east = Kamelopard.convert_coord a
1561
+ end
1442
1562
 
1443
- def west=(a)
1444
- @west = convert_coord a
1445
- end
1563
+ def west=(a)
1564
+ @west = Kamelopard.convert_coord a
1565
+ end
1446
1566
 
1447
- def to_kml(indent = 0, alt = false)
1448
- name = alt ? 'LatLonAltBox' : 'LatLonBox'
1449
- k = <<-latlonbox
1450
- #{ ' ' * indent }<#{ name }>
1451
- #{ ' ' * indent } <north>#{ @north }</north>
1452
- #{ ' ' * indent } <south>#{ @south }</south>
1453
- #{ ' ' * indent } <east>#{ @east }</east>
1454
- #{ ' ' * indent } <west>#{ @west }</west>
1455
- latlonbox
1456
- k << "#{ ' ' * indent } <minAltitude>#{ @minAltitude }</minAltitude>\n" unless @minAltitude.nil?
1457
- k << "#{ ' ' * indent } <maxAltitude>#{ @maxAltitude }</maxAltitude>\n" unless @maxAltitude.nil?
1458
- if (not @minAltitude.nil? or not @maxAltitude.nil?) then
1459
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
1460
- altitudeModeString = "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
1461
- else
1462
- altitudeModeString = "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
1567
+ def to_kml(elem = nil, alt = false)
1568
+ name = alt ? 'LatLonAltBox' : 'LatLonBox'
1569
+ k = REXML::Element.new name
1570
+ [
1571
+ ['north', @north],
1572
+ ['south', @south],
1573
+ ['east', @east],
1574
+ ['west', @west],
1575
+ ['minAltitude', @minAltitude],
1576
+ ['maxAltitude', @maxAltitude]
1577
+ ].each do |a|
1578
+ if not a[1].nil? then
1579
+ m = REXML::Element.new a[0]
1580
+ m.text = a[1]
1581
+ k.elements << m
1582
+ end
1583
+ end
1584
+ if (not @minAltitude.nil? or not @maxAltitude.nil?) then
1585
+ Kamelopard.add_altitudeMode(@altitudeMode, k)
1463
1586
  end
1587
+ m = REXML::Element.new 'rotation'
1588
+ m.text = @rotation
1589
+ k.elements << m
1590
+ elem.elements << k unless elem.nil?
1591
+ k
1464
1592
  end
1465
- k << <<-latlonbox2
1466
- #{ ' ' * indent } <rotation>#{ @rotation }</rotation>
1467
- #{ ' ' * indent }</#{ name }>
1468
- latlonbox2
1469
1593
  end
1470
- end
1471
-
1472
- # Corresponds to KML's gx:LatLonQuad object
1473
- class LatLonQuad
1474
- attr_accessor :lowerLeft, :lowerRight, :upperRight, :upperLeft
1475
- def initialize(lowerLeft, lowerRight, upperRight, upperLeft)
1476
- @lowerLeft = lowerLeft
1477
- @lowerRight = lowerRight
1478
- @upperRight = upperRight
1479
- @upperLeft = upperLeft
1480
- end
1481
-
1482
- def to_kml(indent = 0)
1483
1594
 
1484
- <<-latlonquad
1485
- #{ ' ' * indent }<gx:LatLonQuad>
1486
- #{ ' ' * indent } <coordinates>#{ @lowerLeft.longitude },#{ @lowerLeft.latitude } #{ @lowerRight.longitude },#{ @lowerRight.latitude } #{ @upperRight.longitude },#{ @upperRight.latitude } #{ @upperLeft.longitude },#{ @upperLeft.latitude }</coordinates>
1487
- #{ ' ' * indent }</gx:LatLonQuad>
1488
- latlonquad
1489
- end
1490
- end
1595
+ # Corresponds to KML's gx:LatLonQuad object
1596
+ class LatLonQuad
1597
+ attr_accessor :lowerLeft, :lowerRight, :upperRight, :upperLeft
1598
+ def initialize(lowerLeft, lowerRight, upperRight, upperLeft)
1599
+ @lowerLeft = lowerLeft
1600
+ @lowerRight = lowerRight
1601
+ @upperRight = upperRight
1602
+ @upperLeft = upperLeft
1603
+ end
1491
1604
 
1492
- # Corresponds to KML's GroundOverlay object
1493
- class GroundOverlay < Overlay
1494
- attr_accessor :altitude, :altitudeMode, :latlonbox, :latlonquad
1495
- def initialize(icon, latlonbox = nil, latlonquad = nil, altitude = 0, altitudeMode = :clampToGround)
1496
- super(icon)
1497
- @latlonbox = latlonbox
1498
- @latlonquad = latlonquad
1499
- @altitude = altitude
1500
- @altitudeMode = altitudeMode
1605
+ def to_kml(elem = nil)
1606
+ k = REXML::Element.new 'gx:LatLonQuad'
1607
+ d = REXML::Element.new 'coordinates'
1608
+ d.text = "#{ @lowerLeft.longitude },#{ @lowerLeft.latitude } #{ @lowerRight.longitude },#{ @lowerRight.latitude } #{ @upperRight.longitude },#{ @upperRight.latitude } #{ @upperLeft.longitude },#{ @upperLeft.latitude }"
1609
+ k << d
1610
+ elem << k unless elem.nil?
1611
+ k
1612
+ end
1501
1613
  end
1502
1614
 
1503
- def to_kml(indent = 0)
1504
- raise "Either latlonbox or latlonquad must be non-nil" if @latlonbox.nil? and @latlonquad.nil?
1505
-
1506
- k = "#{ ' ' * indent}<GroundOverlay id=\"#{ @id }\">\n"
1507
- k << super(indent + 4)
1508
- k << "#{ ' ' * indent } <altitude>#{ @altitude }</altitude>\n"
1509
- k << ' ' * indent
1510
- if @altitudeMode == :clampToGround or @altitudeMode == :relativeToGround or @altitudeMode == :absolute then
1511
- k << "#{ ' ' * indent } <altitudeMode>#{ @altitudeMode }</altitudeMode>\n"
1512
- else
1513
- k << "#{ ' ' * indent } <gx:altitudeMode>#{ @altitudeMode }</gx:altitudeMode>\n"
1615
+ # Corresponds to KML's GroundOverlay object
1616
+ class GroundOverlay < Overlay
1617
+ attr_accessor :altitude, :altitudeMode, :latlonbox, :latlonquad
1618
+ def initialize(icon, latlonbox = nil, latlonquad = nil, altitude = 0, altitudeMode = :clampToGround)
1619
+ super(icon)
1620
+ @latlonbox = latlonbox
1621
+ @latlonquad = latlonquad
1622
+ @altitude = altitude
1623
+ @altitudeMode = altitudeMode
1514
1624
  end
1515
- k << @latlonbox.to_kml(indent + 4) unless @latlonbox.nil?
1516
- k << @latlonquad.to_kml(indent + 4) unless @latlonquad.nil?
1517
- k << "#{ ' ' * indent }</GroundOverlay>\n"
1518
- k
1519
- end
1520
- end
1521
1625
 
1522
- # Corresponds to the LOD (Level of Detail) object
1523
- class Lod
1524
- attr_accessor :minpixels, :maxpixels, :minfade, :maxfade
1525
- def initialize(minpixels, maxpixels, minfade, maxfade)
1526
- @minpixels = minpixels
1527
- @maxpixels = maxpixels
1528
- @minfade = minfade
1529
- @maxfade = maxfade
1626
+ def to_kml(elem = nil)
1627
+ raise "Either latlonbox or latlonquad must be non-nil" if @latlonbox.nil? and @latlonquad.nil?
1628
+ k = REXML::Element.new 'GroundOverlay'
1629
+ super k
1630
+ d = REXML::Element.new 'altitude'
1631
+ d.text = @altitude
1632
+ k << d
1633
+ Kamelopard.add_altitudeMode(@altitudeMode, k)
1634
+ @latlonbox.to_kml(k) unless @latlonbox.nil?
1635
+ @latlonquad.to_kml(k) unless @latlonquad.nil?
1636
+ elem << k unless elem.nil?
1637
+ k
1638
+ end
1530
1639
  end
1531
1640
 
1532
- def to_kml(indent = 0)
1641
+ # Corresponds to the LOD (Level of Detail) object
1642
+ class Lod
1643
+ attr_accessor :minpixels, :maxpixels, :minfade, :maxfade
1644
+ def initialize(minpixels, maxpixels, minfade, maxfade)
1645
+ @minpixels = minpixels
1646
+ @maxpixels = maxpixels
1647
+ @minfade = minfade
1648
+ @maxfade = maxfade
1649
+ end
1533
1650
 
1534
- <<-lod
1535
- #{ ' ' * indent }<Lod>
1536
- #{ ' ' * indent } <minLodPixels>#{ @minpixels }</minLodPixels>
1537
- #{ ' ' * indent } <maxLodPixels>#{ @maxpixels }</maxLodPixels>
1538
- #{ ' ' * indent } <minFadeExtent>#{ @minfade }</minFadeExtent>
1539
- #{ ' ' * indent } <maxFadeExtent>#{ @maxfade }</maxFadeExtent>
1540
- #{ ' ' * indent }</Lod>
1541
- lod
1651
+ def to_kml(elem = nil)
1652
+ k = REXML::Element.new 'Lod'
1653
+ m = REXML::Element.new 'minLodPixels'
1654
+ m.text = @minpixels
1655
+ k.elements << m
1656
+ m = REXML::Element.new 'maxLodPixels'
1657
+ m.text = @maxpixels
1658
+ k.elements << m
1659
+ m = REXML::Element.new 'minFadeExtent'
1660
+ m.text = @minfade
1661
+ k.elements << m
1662
+ m = REXML::Element.new 'maxFadeExtent'
1663
+ m.text = @maxfade
1664
+ k.elements << m
1665
+ elem.elements << k unless elem.nil?
1666
+ k
1667
+ end
1542
1668
  end
1543
- end
1544
1669
 
1545
- # Corresponds to the KML Region object
1546
- class Region < KMLObject
1547
- attr_accessor :latlonaltbox, :lod
1670
+ # Corresponds to the KML Region object
1671
+ class Region < Object
1672
+ attr_accessor :latlonaltbox, :lod
1548
1673
 
1549
- def initialize(latlonaltbox, lod)
1550
- super()
1551
- @latlonaltbox = latlonaltbox
1552
- @lod = lod
1553
- end
1674
+ def initialize(latlonaltbox, lod)
1675
+ super()
1676
+ @latlonaltbox = latlonaltbox
1677
+ @lod = lod
1678
+ end
1554
1679
 
1555
- def to_kml(indent = 0)
1556
- k = "#{' ' * indent}<Region id=\"#{@id}\">\n"
1557
- k << @latlonaltbox.to_kml(indent + 4, true) unless @latlonaltbox.nil?
1558
- k << @lod.to_kml(indent + 4) unless @lod.nil?
1559
- k << "#{' ' * indent}</Region>\n"
1560
- k
1680
+ def to_kml(elem = nil)
1681
+ k = REXML::Element.new 'Region'
1682
+ super(k)
1683
+ @latlonaltbox.to_kml(k, true) unless @latlonaltbox.nil?
1684
+ @lod.to_kml(k) unless @lod.nil?
1685
+ elem.elements << k unless elem.nil?
1686
+ k
1687
+ end
1561
1688
  end
1562
- end
1563
1689
 
1564
- # Sub-object in the KML Model class
1565
- class Orientation
1566
- attr_accessor :heading, :tilt, :roll
1567
- def initialize(heading, tilt, roll)
1568
- @heading = heading
1569
- # Although the KML reference by Google is clear on these ranges, Google Earth
1570
- # supports values outside the ranges, and sometimes it's useful to use
1571
- # them. So I'm turning off this error checking
1572
- # raise "Heading should be between 0 and 360 inclusive; you gave #{ heading }" unless @heading <= 360 and @heading >= 0
1573
- @tilt = tilt
1574
- # raise "Tilt should be between 0 and 180 inclusive; you gave #{ tilt }" unless @tilt <= 180 and @tilt >= 0
1575
- @roll = roll
1576
- # raise "Roll should be between 0 and 180 inclusive; you gave #{ roll }" unless @roll <= 180 and @roll >= 0
1577
- end
1690
+ # Sub-object in the KML Model class
1691
+ class Orientation
1692
+ attr_accessor :heading, :tilt, :roll
1693
+ def initialize(heading, tilt, roll)
1694
+ @heading = heading
1695
+ # Although the KML reference by Google is clear on these ranges, Google Earth
1696
+ # supports values outside the ranges, and sometimes it's useful to use
1697
+ # them. So I'm turning off this error checking
1698
+ #raise "Heading should be between 0 and 360 inclusive; you gave #{ heading }" unless @heading <= 360 and @heading >= 0
1699
+ @tilt = tilt
1700
+ #raise "Tilt should be between 0 and 180 inclusive; you gave #{ tilt }" unless @tilt <= 180 and @tilt >= 0
1701
+ @roll = roll
1702
+ #raise "Roll should be between 0 and 180 inclusive; you gave #{ roll }" unless @roll <= 180 and @roll >= 0
1703
+ end
1578
1704
 
1579
- def to_kml(indent = 0)
1580
- k = "#{ ' ' * indent }<Orientation>\n"
1581
- k << "#{ ' ' * indent } <heading>#{ @heading }</heading>\n"
1582
- k << "#{ ' ' * indent } <tilt>#{ @tilt }</tilt>\n"
1583
- k << "#{ ' ' * indent } <roll>#{ @roll }</roll>\n"
1584
- k << "#{ ' ' * indent }</Orientation>\n"
1585
- k
1705
+ def to_kml(elem = nil)
1706
+ x = REXML::Element.new 'Orientation'
1707
+ {
1708
+ :heading => @heading,
1709
+ :tilt => @tilt,
1710
+ :roll => @roll
1711
+ }.each do |k, v|
1712
+ d = REXML::Element.new k.to_s
1713
+ d.text = v
1714
+ x << d
1715
+ end
1716
+ elem << x unless elem.nil?
1717
+ x
1718
+ end
1586
1719
  end
1587
- end
1588
1720
 
1589
- # Sub-object in the KML Model class
1590
- class Scale
1591
- attr_accessor :x, :y, :z
1592
- def initialize(x, y, z = 1)
1593
- @x = x
1594
- @y = y
1595
- @z = z
1596
- end
1721
+ # Sub-object in the KML Model class
1722
+ class Scale
1723
+ attr_accessor :x, :y, :z
1724
+ def initialize(x, y, z = 1)
1725
+ @x = x
1726
+ @y = y
1727
+ @z = z
1728
+ end
1597
1729
 
1598
- def to_kml(indent = 0)
1599
- k = "#{ ' ' * indent }<Scale>\n"
1600
- k << "#{ ' ' * indent } <x>#{ x }</x>\n"
1601
- k << "#{ ' ' * indent } <y>#{ y }</y>\n"
1602
- k << "#{ ' ' * indent } <z>#{ z }</z>\n"
1603
- k << "#{ ' ' * indent }</Scale>\n"
1730
+ def to_kml(elem = nil)
1731
+ x = REXML::Element.new 'Scale'
1732
+ {
1733
+ :x => @x,
1734
+ :y => @y,
1735
+ :z => @z
1736
+ }.each do |k, v|
1737
+ d = REXML::Element.new k.to_s
1738
+ d.text = v
1739
+ x << d
1740
+ end
1741
+ elem << x unless elem.nil?
1742
+ x
1743
+ end
1604
1744
  end
1605
- end
1606
1745
 
1607
- # Sub-object in the KML ResourceMap class
1608
- class Alias
1609
- attr_accessor :targetHref, :sourceHref
1610
- def initialize(targetHref = nil, sourceHref = nil)
1611
- @targetHref = targetHref
1612
- @sourceHref = sourceHref
1613
- end
1746
+ # Sub-object in the KML ResourceMap class
1747
+ class Alias
1748
+ attr_accessor :targetHref, :sourceHref
1749
+ def initialize(targetHref = nil, sourceHref = nil)
1750
+ @targetHref = targetHref
1751
+ @sourceHref = sourceHref
1752
+ end
1614
1753
 
1615
- def to_kml(indent = 0)
1616
- k = "#{ ' ' * indent }<Alias>\n"
1617
- k << "#{ ' ' * indent } <targetHref>#{ @targetHref }</targetHref>\n"
1618
- k << "#{ ' ' * indent } <sourceHref>#{ @sourceHref }</sourceHref>\n"
1619
- k << "#{ ' ' * indent }</Alias>\n"
1620
- k
1754
+ def to_kml(elem = nil)
1755
+ x = REXML::Element.new 'Alias'
1756
+ {
1757
+ :targetHref => @targetHref,
1758
+ :sourceHref => @sourceHref,
1759
+ }.each do |k, v|
1760
+ d = REXML::Element.new k.to_s
1761
+ d.text = v
1762
+ x << d
1763
+ end
1764
+ elem << x unless elem.nil?
1765
+ x
1766
+ end
1621
1767
  end
1622
- end
1623
1768
 
1624
- # Sub-object in the KML Model class
1625
- class ResourceMap
1626
- attr_accessor :aliases
1627
- def initialize(aliases = [])
1628
- @aliases = []
1629
- if not aliases.nil? then
1630
- if aliases.kind_of? Enumerable then
1631
- @aliases += aliases
1632
- else
1633
- @aliases << aliases
1769
+ # Sub-object in the KML Model class
1770
+ class ResourceMap
1771
+ attr_accessor :aliases
1772
+ def initialize(aliases = [])
1773
+ @aliases = []
1774
+ if not aliases.nil? then
1775
+ if aliases.kind_of? Enumerable then
1776
+ @aliases += aliases
1777
+ else
1778
+ @aliases << aliases
1779
+ end
1634
1780
  end
1635
1781
  end
1636
- end
1637
1782
 
1638
- def to_kml(indent = 0)
1639
- return '' if @aliases.size == 0
1640
- k = "#{ ' ' * indent }<ResourceMap>\n"
1641
- k << "#{ ' ' * indent }</ResourceMap>\n"
1642
- @aliases.each do |a| k << a.to_kml(indent + 4) end
1643
- k
1783
+ def to_kml(elem = nil)
1784
+ k = REXML::Element.new 'ResourceMap'
1785
+ @aliases.each do |a| k << a.to_kml(k) end
1786
+ elem << k unless elem.nil?
1787
+ k
1788
+ end
1644
1789
  end
1645
- end
1646
1790
 
1647
- # Corresponds to KML's Link object
1648
- class Link < KMLObject
1649
- attr_accessor :href, :refreshMode, :refreshInterval, :viewRefreshMode, :viewBoundScale, :viewFormat, :httpQuery
1650
- def initialize(href = '', refreshMode = :onChange, viewRefreshMode = :never)
1651
- super()
1652
- @href = href
1653
- @refreshMode = refreshMode
1654
- @viewRefreshMode = viewRefreshMode
1655
- end
1791
+ # Corresponds to KML's Link object
1792
+ class Link < Object
1793
+ attr_accessor :href, :refreshMode, :refreshInterval, :viewRefreshMode, :viewBoundScale, :viewFormat, :httpQuery
1794
+ def initialize(href = '', refreshMode = :onChange, viewRefreshMode = :never)
1795
+ super()
1796
+ @href = href
1797
+ @refreshMode = refreshMode
1798
+ @viewRefreshMode = viewRefreshMode
1799
+ end
1656
1800
 
1657
- def to_kml(indent = 0)
1658
- k = "#{ ' ' * indent }<Link id=\"#{ @id }\">\n"
1659
- k << "#{ ' ' * indent } <href>#{ @href }</href>\n"
1660
- k << "#{ ' ' * indent } <refreshMode>#{ @refreshMode }</refreshMode>\n"
1661
- k << "#{ ' ' * indent } <viewRefreshMode>#{ @viewRefreshMode }</viewRefreshMode>\n"
1662
- k << "#{ ' ' * indent } <refreshInterval>#{ @refreshInterval }</refreshInterval>\n" unless @refreshInterval.nil?
1663
- k << "#{ ' ' * indent } <viewBoundScale>#{ @viewBoundScale }</viewBoundScale>\n" unless @viewBoundScale.nil?
1664
- k << "#{ ' ' * indent } <viewFormat>#{ @viewFormat }</viewFormat>\n" unless @viewFormat.nil?
1665
- k << "#{ ' ' * indent } <httpQuery>#{ @httpQuery }</httpQuery>\n" unless @httpQuery.nil?
1666
- k << "#{ ' ' * indent }</Link>\n"
1667
- k
1801
+ def to_kml(elem = nil)
1802
+ x = REXML::Element.new 'Link'
1803
+ super x
1804
+ {
1805
+ :href => @href,
1806
+ :refreshMode => @refreshMode,
1807
+ :viewRefreshMode => @viewRefreshMode,
1808
+ }.each do |k, v|
1809
+ d = REXML::Element.new k.to_s
1810
+ d.text = v
1811
+ x << d
1812
+ end
1813
+ Kamelopard.kml_array(x, [
1814
+ [ @refreshInterval, 'refreshInterval' ],
1815
+ [ @viewBoundScale, 'viewBoundScale' ],
1816
+ [ @viewFormat, 'viewFormat' ],
1817
+ [ @httpQuery, 'httpQuery' ]
1818
+ ])
1819
+ elem << x unless elem.nil?
1820
+ x
1821
+ end
1668
1822
  end
1669
- end
1670
1823
 
1671
- # Corresponds to the KML Model class
1672
- class Model < Geometry
1673
- attr_accessor :link, :location, :orientation, :scale, :resourceMap
1674
-
1675
- # location should be a KMLPoint, or some object that can behave like one,
1676
- # including a Placemark. Model will get its Location and altitudeMode data
1677
- # from this attribute
1678
- def initialize(link, location, orientation, scale, resourceMap)
1679
- super()
1680
- @link = link
1681
- @location = location
1682
- @orientation = orientation
1683
- @scale = scale
1684
- @resourceMap = resourceMap
1685
- end
1824
+ # Corresponds to the KML Model class
1825
+ class Model < Geometry
1826
+ attr_accessor :link, :location, :orientation, :scale, :resourceMap
1827
+
1828
+ # location should be a Point, or some object that can behave like one,
1829
+ # including a Placemark. Model will get its Location and altitudeMode data
1830
+ # from this attribute
1831
+ def initialize(link, location, orientation, scale, resourceMap)
1832
+ super()
1833
+ @link = link
1834
+ @location = location
1835
+ @orientation = orientation
1836
+ @scale = scale
1837
+ @resourceMap = resourceMap
1838
+ end
1686
1839
 
1687
- def to_kml(indent = 0)
1688
- k = "#{ ' ' * indent }<Model id=\"#{ @id }\">\n"
1689
- k << @link.to_kml(indent + 4)
1690
- if @location.altitudeMode == :clampToGround or @location.altitudeMode == :relativeToGround or @location.altitudeMode == :absolute then
1691
- k << "#{ ' ' * indent } <altitudeMode>#{ @location.altitudeMode }</altitudeMode>\n"
1692
- else
1693
- k << "#{ ' ' * indent } <gx:altitudeMode>#{ @location.altitudeMode }</gx:altitudeMode>\n"
1694
- end
1695
- k << "#{ ' ' * indent } <Location>\n"
1696
- k << "#{ ' ' * indent } <longitude>#{ @location.longitude }</longitude>\n"
1697
- k << "#{ ' ' * indent } <latitude>#{ @location.latitude }</latitude>\n"
1698
- k << "#{ ' ' * indent } <altitude>#{ @location.altitude }</altitude>\n"
1699
- k << "#{ ' ' * indent } </Location>\n"
1700
- k << @orientation.to_kml(indent + 4)
1701
- k << @scale.to_kml(indent + 4)
1702
- k << @resourceMap.to_kml(indent + 4)
1703
- k << "#{ ' ' * indent }</Model>\n"
1704
- k
1840
+ def to_kml(elem = nil)
1841
+ x = REXML::Element.new 'Model'
1842
+ super x
1843
+ loc = REXML::Element.new 'Location'
1844
+ {
1845
+ :longitude => @location.longitude,
1846
+ :latitude => @location.latitude,
1847
+ :altitude => @location.altitude,
1848
+ }.each do |k, v|
1849
+ d = REXML::Element.new k.to_s
1850
+ d.text = v
1851
+ loc << d
1852
+ end
1853
+ x << loc
1854
+ Kamelopard.add_altitudeMode(@location.altitudeMode, x)
1855
+ @link.to_kml x
1856
+ @orientation.to_kml x
1857
+ @scale.to_kml x
1858
+ @resourceMap.to_kml x
1859
+ elem << x unless elem.nil?
1860
+ x
1861
+ end
1705
1862
  end
1863
+
1706
1864
  end
1865
+ # End of Kamelopard module