kamelopard 0.0.3 → 0.0.4

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