kamelopard 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/kamelopard/classes.rb +1574 -1415
- data/lib/kamelopard/functions.rb +5 -1
- data/lib/kamelopard/geocode.rb +1 -0
- metadata +41 -20
data/lib/kamelopard/classes.rb
CHANGED
@@ -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
|
-
|
8
|
-
require '
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@@sequence
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
88
|
-
|
89
|
-
|
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
|
-
#
|
93
|
-
def
|
94
|
-
if
|
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
|
-
|
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
|
-
#
|
103
|
-
|
104
|
-
|
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
|
-
|
107
|
-
class
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
106
|
+
def initialize(comment = nil)
|
107
|
+
@id = "#{self.class.name.gsub('Kamelopard::', '')}_#{ Kamelopard.get_next_id }"
|
108
|
+
@comment = comment.gsub(/</, '<') 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
|
-
|
119
|
-
|
120
|
+
|
121
|
+
# Abstract base class for Point and several other classes
|
122
|
+
class Geometry < Object
|
120
123
|
end
|
121
124
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
180
|
+
def to_kml(elem = nil)
|
181
|
+
e = REXML::Element.new 'coordinates'
|
182
|
+
t = ''
|
159
183
|
@coordinates.each do |a|
|
160
|
-
|
161
|
-
|
162
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
193
|
+
# Alias for add_element
|
194
|
+
def <<(a)
|
195
|
+
add_element a
|
196
|
+
end
|
173
197
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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
|
203
|
-
|
204
|
-
|
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
|
-
#
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
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
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
-
#
|
275
|
-
|
276
|
-
|
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
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
-
#
|
303
|
-
|
304
|
-
|
305
|
-
end
|
294
|
+
# Corresponds to KML's LinearRing object
|
295
|
+
class LinearRing < Geometry
|
296
|
+
attr_accessor :altitudeOffset, :extrude, :tessellate, :altitudeMode, :coordinates
|
306
297
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
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
|
-
#
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
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
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
-
|
355
|
-
|
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
|
-
|
359
|
-
|
360
|
-
|
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
|
-
|
363
|
-
|
364
|
-
|
365
|
+
def point=(point)
|
366
|
+
@point.longitude = point.longitude
|
367
|
+
@point.latitude = point.latitude
|
368
|
+
@point.altitude = point.altitude
|
369
|
+
end
|
365
370
|
|
366
|
-
|
367
|
-
|
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
|
-
|
375
|
-
|
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
|
-
|
383
|
-
|
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
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
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
|
-
|
408
|
-
|
409
|
-
@
|
410
|
-
|
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
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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
|
-
|
424
|
-
|
425
|
-
|
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
|
-
|
428
|
-
|
429
|
-
raise 'Option value must be boolean'
|
439
|
+
def [](a)
|
440
|
+
return @options[a]
|
430
441
|
end
|
431
|
-
|
432
|
-
|
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
|
-
|
441
|
-
|
442
|
-
|
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
|
-
|
445
|
-
|
446
|
-
|
460
|
+
def range
|
461
|
+
raise "The range element is part of LookAt objects, not Camera objects"
|
462
|
+
end
|
447
463
|
|
448
|
-
|
449
|
-
|
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
|
-
|
456
|
-
|
457
|
-
|
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
|
-
|
460
|
-
|
461
|
-
|
475
|
+
def roll
|
476
|
+
raise "The roll element is part of Camera objects, not LookAt objects"
|
477
|
+
end
|
462
478
|
|
463
|
-
|
464
|
-
|
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 <
|
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
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
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
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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
|
-
|
504
|
-
|
505
|
-
|
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
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
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
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
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
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
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 <
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
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
|
-
|
548
|
-
|
549
|
-
|
575
|
+
def timestamp
|
576
|
+
@timeprimitive
|
577
|
+
end
|
550
578
|
|
551
|
-
|
552
|
-
|
553
|
-
|
579
|
+
def timespan
|
580
|
+
@timeprimitive
|
581
|
+
end
|
554
582
|
|
555
|
-
|
556
|
-
|
557
|
-
|
583
|
+
def timestamp=(t)
|
584
|
+
@timeprimitive = t
|
585
|
+
end
|
558
586
|
|
559
|
-
|
560
|
-
|
561
|
-
|
587
|
+
def timespan=(t)
|
588
|
+
@timeprimitive = t
|
589
|
+
end
|
562
590
|
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
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
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
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
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
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
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
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
|
-
#
|
630
|
-
|
631
|
-
|
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
|
-
|
667
|
+
# Corresponds to KML's Folder object.
|
668
|
+
class Folder < Container
|
669
|
+
attr_accessor :styles, :folders, :parent_folder
|
638
670
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
671
|
+
def initialize(name = nil)
|
672
|
+
super()
|
673
|
+
@name = name
|
674
|
+
@styles = []
|
675
|
+
@folders = []
|
676
|
+
Document.instance.folders << self
|
677
|
+
end
|
646
678
|
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
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
|
-
|
654
|
-
|
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
|
-
|
661
|
-
|
662
|
-
|
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
|
-
#
|
666
|
-
|
667
|
-
|
668
|
-
|
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
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
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
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
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
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
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
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
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(
|
705
|
-
|
706
|
-
end
|
737
|
+
# def styles_to_kml(elem = nil)
|
738
|
+
# end
|
707
739
|
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
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
|
-
|
722
|
-
|
757
|
+
def to_kml
|
758
|
+
d = REXML::Element.new 'Document'
|
759
|
+
super(d)
|
723
760
|
|
724
|
-
|
725
|
-
|
761
|
+
# Print styles first
|
762
|
+
@styles.map do |a| a.to_kml(d) unless a.attached? end
|
726
763
|
|
727
|
-
|
728
|
-
|
729
|
-
|
764
|
+
# then folders
|
765
|
+
@folders.map do |a|
|
766
|
+
a.to_kml(d) unless a.has_parent?
|
767
|
+
end
|
730
768
|
|
731
|
-
|
732
|
-
|
733
|
-
end
|
769
|
+
# then tours
|
770
|
+
@tours.map do |a| a.to_kml(d) end
|
734
771
|
|
735
|
-
|
736
|
-
|
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
|
-
|
751
|
-
|
752
|
-
|
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
|
-
|
755
|
-
|
756
|
-
|
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
|
-
|
760
|
-
|
761
|
-
|
795
|
+
def colorMode=(a)
|
796
|
+
validate_colorMode a
|
797
|
+
@colorMode = a
|
798
|
+
end
|
762
799
|
|
763
|
-
|
764
|
-
|
765
|
-
|
800
|
+
def alpha
|
801
|
+
@color[0,2]
|
802
|
+
end
|
766
803
|
|
767
|
-
|
768
|
-
|
769
|
-
|
804
|
+
def alpha=(a)
|
805
|
+
@color[0,2] = a
|
806
|
+
end
|
770
807
|
|
771
|
-
|
772
|
-
|
773
|
-
|
808
|
+
def blue
|
809
|
+
@color[2,2]
|
810
|
+
end
|
774
811
|
|
775
|
-
|
776
|
-
|
777
|
-
|
812
|
+
def blue=(a)
|
813
|
+
@color[2,2] = a
|
814
|
+
end
|
778
815
|
|
779
|
-
|
780
|
-
|
781
|
-
|
816
|
+
def green
|
817
|
+
@color[4,2]
|
818
|
+
end
|
782
819
|
|
783
|
-
|
784
|
-
|
785
|
-
|
820
|
+
def green=(a)
|
821
|
+
@color[4,2] = a
|
822
|
+
end
|
786
823
|
|
787
|
-
|
788
|
-
|
789
|
-
|
824
|
+
def red
|
825
|
+
@color[6,2]
|
826
|
+
end
|
790
827
|
|
791
|
-
|
828
|
+
def red=(a)
|
829
|
+
@color[6,2] = a
|
830
|
+
end
|
792
831
|
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
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 <
|
804
|
-
|
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
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
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
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
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
|
-
|
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
|
-
|
840
|
-
|
841
|
-
|
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
|
-
|
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
|
-
|
850
|
-
|
851
|
-
|
899
|
+
def initialize(href = nil)
|
900
|
+
@href = href
|
901
|
+
@id = "Icon_#{ Kamelopard.get_next_id }"
|
902
|
+
end
|
852
903
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
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
|
-
|
926
|
+
# Corresponds to KML's IconStyle object.
|
927
|
+
class IconStyle < ColorStyle
|
928
|
+
attr_accessor :scale, :heading, :hotspot, :icon
|
875
929
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
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
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
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
|
-
|
959
|
+
# Corresponds to KML's LabelStyle object
|
960
|
+
class LabelStyle < ColorStyle
|
961
|
+
attr_accessor :scale
|
900
962
|
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
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
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
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
|
-
|
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
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
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
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
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
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
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
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
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
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
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
|
-
|
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
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
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
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
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
|
-
|
1011
|
-
|
1012
|
-
|
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
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
end
|
1018
|
-
end
|
1074
|
+
def attached?
|
1075
|
+
@attached
|
1076
|
+
end
|
1019
1077
|
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
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
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
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
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
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
|
-
|
1059
|
-
|
1060
|
-
|
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
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
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
|
-
|
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
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
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
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
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
|
-
|
1109
|
-
|
1110
|
-
|
1176
|
+
def to_s
|
1177
|
+
"Placemark id #{ @id } named #{ @name }"
|
1178
|
+
end
|
1111
1179
|
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1180
|
+
def longitude
|
1181
|
+
@geometry.longitude
|
1182
|
+
end
|
1115
1183
|
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1184
|
+
def latitude
|
1185
|
+
@geometry.latitude
|
1186
|
+
end
|
1119
1187
|
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1188
|
+
def altitude
|
1189
|
+
@geometry.altitude
|
1190
|
+
end
|
1123
1191
|
|
1124
|
-
|
1125
|
-
|
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
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
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
|
-
#
|
1142
|
-
#
|
1143
|
-
class
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
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
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
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
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
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
|
-
|
1194
|
-
|
1195
|
-
|
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
|
-
|
1199
|
-
|
1200
|
-
#
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
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
|
-
#
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
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
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
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:
|
1226
|
-
class
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
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
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
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:
|
1241
|
-
class
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
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
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
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:
|
1258
|
-
class
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
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
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
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
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
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
|
-
|
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
|
-
|
1284
|
-
|
1285
|
-
|
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
|
-
|
1388
|
+
# Abstract class corresponding to the KML Overlay object
|
1389
|
+
class Overlay < Feature
|
1390
|
+
attr_accessor :color, :drawOrder, :icon
|
1292
1391
|
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
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
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
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
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
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
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
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
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
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
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
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
|
-
|
1471
|
+
# Supporting object for the PhotoOverlay class
|
1472
|
+
class ImagePyramid
|
1473
|
+
attr_accessor :tileSize, :maxWidth, :maxHeight, :gridOrigin
|
1365
1474
|
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
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
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
1382
|
-
|
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
|
-
|
1499
|
+
# Corresponds to KML's PhotoOverlay class
|
1500
|
+
class PhotoOverlay < Overlay
|
1501
|
+
attr_accessor :rotation, :viewvolume, :imagepyramid, :point, :shape
|
1389
1502
|
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
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
|
-
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1408
|
-
|
1409
|
-
|
1410
|
-
|
1411
|
-
|
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
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
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
|
-
|
1432
|
-
|
1433
|
-
|
1551
|
+
def north=(a)
|
1552
|
+
@north = Kamelopard.convert_coord a
|
1553
|
+
end
|
1434
1554
|
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1555
|
+
def south=(a)
|
1556
|
+
@south = Kamelopard.convert_coord a
|
1557
|
+
end
|
1438
1558
|
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1559
|
+
def east=(a)
|
1560
|
+
@east = Kamelopard.convert_coord a
|
1561
|
+
end
|
1442
1562
|
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1563
|
+
def west=(a)
|
1564
|
+
@west = Kamelopard.convert_coord a
|
1565
|
+
end
|
1446
1566
|
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
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
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
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
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
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
|
-
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
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
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
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
|
-
|
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
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
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 <
|
1547
|
-
|
1670
|
+
# Corresponds to the KML Region object
|
1671
|
+
class Region < Object
|
1672
|
+
attr_accessor :latlonaltbox, :lod
|
1548
1673
|
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1674
|
+
def initialize(latlonaltbox, lod)
|
1675
|
+
super()
|
1676
|
+
@latlonaltbox = latlonaltbox
|
1677
|
+
@lod = lod
|
1678
|
+
end
|
1554
1679
|
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
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
|
-
|
1567
|
-
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
#
|
1573
|
-
|
1574
|
-
#
|
1575
|
-
|
1576
|
-
#
|
1577
|
-
|
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
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
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
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
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
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
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
|
-
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
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
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
|
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
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
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
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
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 <
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
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
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
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
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
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
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
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
|