kamelopard 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/kamelopard/classes.rb +84 -22
- data/lib/kamelopard/functions.rb +161 -24
- data/lib/kamelopard/pointlist.rb +51 -76
- metadata +4 -4
data/lib/kamelopard/classes.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
# vim:ts=4:sw=4:et:smartindent:nowrap
|
2
3
|
|
3
4
|
# Classes to manage various KML objects. See
|
4
5
|
# http://code.google.com/apis/kml/documentation/kmlreference.html for a
|
5
6
|
# description of KML
|
6
7
|
|
7
|
-
# XXX gx:balloonVisibility isn't represented here. Fix that.
|
8
|
-
|
9
8
|
module Kamelopard
|
10
9
|
require 'singleton'
|
11
10
|
require 'kamelopard/pointlist'
|
12
11
|
require 'xml'
|
13
12
|
require 'yaml'
|
13
|
+
require 'erb'
|
14
14
|
|
15
15
|
@@sequence = 0
|
16
16
|
@@id_prefix = ''
|
@@ -396,7 +396,7 @@ module Kamelopard
|
|
396
396
|
else
|
397
397
|
a = point
|
398
398
|
end
|
399
|
-
@point = Point.new a.longitude, a.latitude, a.altitude
|
399
|
+
@point = Point.new a.longitude, a.latitude, a.altitude, :altitudeMode => a.altitudeMode
|
400
400
|
end
|
401
401
|
end
|
402
402
|
|
@@ -707,7 +707,7 @@ module Kamelopard
|
|
707
707
|
def styleUrl=(a)
|
708
708
|
if a.is_a? String then
|
709
709
|
@styleUrl = a
|
710
|
-
elsif a.respond_to?
|
710
|
+
elsif a.respond_to? :kml_id then
|
711
711
|
@styleUrl = "##{ a.kml_id }"
|
712
712
|
else
|
713
713
|
@styleUrl = a.to_s
|
@@ -870,6 +870,53 @@ module Kamelopard
|
|
870
870
|
@folders.last
|
871
871
|
end
|
872
872
|
|
873
|
+
# Makes a screenoverlay with a balloon containing links to the tours in this document
|
874
|
+
# The erb argument contains ERB to populate the description. It can be left nil
|
875
|
+
# The options hash is passed to the ScreenOverlay constructor
|
876
|
+
def make_tour_index(erb = nil, options = {})
|
877
|
+
options[:name] ||= 'Tour index'
|
878
|
+
|
879
|
+
options[:screenXY] ||= Kamelopard::XY.new(0.0, 1.0, :fraction, :fraction)
|
880
|
+
options[:overlayXY] ||= Kamelopard::XY.new(0.0, 1.0, :fraction, :fraction)
|
881
|
+
s = Kamelopard::ScreenOverlay.new options
|
882
|
+
t = ERB.new( erb || %{
|
883
|
+
<html>
|
884
|
+
<body>
|
885
|
+
<ul><% @tours.each do |t| %>
|
886
|
+
<li><a href="#<%= t.kml_id %>;flyto"><% if t.icon.nil? %><%= t.name %><% else %><img src="<%= t.icon %>" /><% end %></a></li>
|
887
|
+
<% end %></ul>
|
888
|
+
</body>
|
889
|
+
</html>
|
890
|
+
})
|
891
|
+
|
892
|
+
s.description = XML::Node.new_cdata t.result(binding)
|
893
|
+
s.balloonVisibility = 1
|
894
|
+
|
895
|
+
balloon_au = [0, 1].collect do |v|
|
896
|
+
au = Kamelopard::AnimatedUpdate.new [], :standalone => true
|
897
|
+
a = XML::Node.new 'Change'
|
898
|
+
b = XML::Node.new 'ScreenOverlay'
|
899
|
+
b.attributes['targetId'] = s.kml_id
|
900
|
+
c = XML::Node.new 'gx:balloonVisibility'
|
901
|
+
c << XML::Node.new_text(v.to_s)
|
902
|
+
b << c
|
903
|
+
a << b
|
904
|
+
au << a
|
905
|
+
au
|
906
|
+
end
|
907
|
+
|
908
|
+
# Handle hiding and displaying the index
|
909
|
+
@tours.each do |t|
|
910
|
+
q = Wait.new(0.1, :standalone => true)
|
911
|
+
t.playlist.unshift balloon_au[0]
|
912
|
+
t.playlist.unshift q
|
913
|
+
t.playlist << balloon_au[1]
|
914
|
+
t.playlist << q
|
915
|
+
end
|
916
|
+
|
917
|
+
s
|
918
|
+
end
|
919
|
+
|
873
920
|
def get_kml_document
|
874
921
|
k = XML::Document.new
|
875
922
|
# XXX fix this
|
@@ -1304,7 +1351,7 @@ module Kamelopard
|
|
1304
1351
|
# Corresponds to KML's Placemark objects. The geometry attribute requires a
|
1305
1352
|
# descendant of Geometry
|
1306
1353
|
class Placemark < Feature
|
1307
|
-
attr_accessor :name, :geometry
|
1354
|
+
attr_accessor :name, :geometry, :balloonVisibility
|
1308
1355
|
|
1309
1356
|
def initialize(name = nil, options = {})
|
1310
1357
|
super
|
@@ -1315,6 +1362,11 @@ module Kamelopard
|
|
1315
1362
|
k = XML::Node.new 'Placemark'
|
1316
1363
|
super k
|
1317
1364
|
@geometry.to_kml(k) unless @geometry.nil?
|
1365
|
+
if ! @balloonVisibility.nil? then
|
1366
|
+
x = XML::Node.new 'gx:balloonVisibility'
|
1367
|
+
x << ( @balloonVisibility ? 1 : 0 )
|
1368
|
+
k << x
|
1369
|
+
end
|
1318
1370
|
elem << k unless elem.nil?
|
1319
1371
|
k
|
1320
1372
|
end
|
@@ -1352,9 +1404,14 @@ module Kamelopard
|
|
1352
1404
|
|
1353
1405
|
# Abstract class corresponding to KML's gx:TourPrimitive object. Tours are made up
|
1354
1406
|
# of descendants of these.
|
1407
|
+
# The :standalone option affects only initialization; there's no point in
|
1408
|
+
# doing anything with it after initialization. It determines whether the
|
1409
|
+
# TourPrimitive object is added to the current tour or not
|
1355
1410
|
class TourPrimitive < Object
|
1411
|
+
attr_accessor :standalone
|
1412
|
+
|
1356
1413
|
def initialize(options = {})
|
1357
|
-
Document.instance.tour << self
|
1414
|
+
Document.instance.tour << self unless options[:standalone]
|
1358
1415
|
super
|
1359
1416
|
end
|
1360
1417
|
end
|
@@ -1526,18 +1583,19 @@ module Kamelopard
|
|
1526
1583
|
|
1527
1584
|
# Corresponds to a KML gx:Tour object
|
1528
1585
|
class Tour < Object
|
1529
|
-
attr_accessor :name, :description, :last_abs_view
|
1586
|
+
attr_accessor :name, :description, :last_abs_view, :playlist, :icon
|
1587
|
+
|
1530
1588
|
def initialize(name = nil, description = nil)
|
1531
1589
|
super()
|
1532
1590
|
@name = name
|
1533
1591
|
@description = description
|
1534
|
-
@
|
1592
|
+
@playlist = []
|
1535
1593
|
Document.instance.tours << self
|
1536
1594
|
end
|
1537
1595
|
|
1538
1596
|
# Add another element to this Tour
|
1539
1597
|
def <<(a)
|
1540
|
-
@
|
1598
|
+
@playlist << a
|
1541
1599
|
@last_abs_view = a.view if a.kind_of? FlyTo
|
1542
1600
|
end
|
1543
1601
|
|
@@ -1549,7 +1607,7 @@ module Kamelopard
|
|
1549
1607
|
[ @description, 'description' ],
|
1550
1608
|
])
|
1551
1609
|
p = XML::Node.new 'gx:Playlist'
|
1552
|
-
@
|
1610
|
+
@playlist.map do |a| a.to_kml p end
|
1553
1611
|
k << p
|
1554
1612
|
elem << k unless elem.nil?
|
1555
1613
|
k
|
@@ -1580,7 +1638,7 @@ module Kamelopard
|
|
1580
1638
|
|
1581
1639
|
# Corresponds to KML's ScreenOverlay object
|
1582
1640
|
class ScreenOverlay < Overlay
|
1583
|
-
attr_accessor :overlayXY, :screenXY, :rotationXY, :size, :rotation
|
1641
|
+
attr_accessor :overlayXY, :screenXY, :rotationXY, :size, :rotation, :balloonVisibility
|
1584
1642
|
|
1585
1643
|
def to_kml(elem = nil)
|
1586
1644
|
k = XML::Node.new 'ScreenOverlay'
|
@@ -1594,6 +1652,11 @@ module Kamelopard
|
|
1594
1652
|
d << @rotation.to_s
|
1595
1653
|
k << d
|
1596
1654
|
end
|
1655
|
+
if ! @balloonVisibility.nil? then
|
1656
|
+
x = XML::Node.new 'gx:balloonVisibility'
|
1657
|
+
x << ( @balloonVisibility ? 1 : 0 )
|
1658
|
+
k << x
|
1659
|
+
end
|
1597
1660
|
elem << k unless elem.nil?
|
1598
1661
|
k
|
1599
1662
|
end
|
@@ -1995,10 +2058,10 @@ module Kamelopard
|
|
1995
2058
|
end
|
1996
2059
|
x << loc
|
1997
2060
|
Kamelopard.add_altitudeMode(@location.altitudeMode, x)
|
1998
|
-
@link.to_kml x
|
1999
|
-
@orientation.to_kml x
|
2000
|
-
@scale.to_kml x
|
2001
|
-
@resourceMap.to_kml x
|
2061
|
+
@link.to_kml x unless @link.nil?
|
2062
|
+
@orientation.to_kml x unless @orientation.nil?
|
2063
|
+
@scale.to_kml x unless @scale.nil?
|
2064
|
+
@resourceMap.to_kml x unless @resourceMap.nil?
|
2002
2065
|
elem << x unless elem.nil?
|
2003
2066
|
x
|
2004
2067
|
end
|
@@ -2077,12 +2140,12 @@ module Kamelopard
|
|
2077
2140
|
attr_accessor :refreshVisibility, :flyToView, :link
|
2078
2141
|
|
2079
2142
|
def initialize(href = '', options = {})
|
2080
|
-
|
2081
|
-
@
|
2082
|
-
|
2083
|
-
@link = Link.new(href, refreshMode, viewRefreshMode)
|
2084
|
-
@refreshVisibility
|
2085
|
-
@flyToView
|
2143
|
+
super(( options[:name] || ''), options)
|
2144
|
+
@refreshMode ||= :onChange
|
2145
|
+
@viewRefreshMode ||= :never
|
2146
|
+
@link = Link.new(href, :refreshMode => @refreshMode, :viewRefreshMode => @viewRefreshMode)
|
2147
|
+
@refreshVisibility ||= 0
|
2148
|
+
@flyToView ||= 0
|
2086
2149
|
end
|
2087
2150
|
|
2088
2151
|
def refreshMode
|
@@ -2147,6 +2210,5 @@ module Kamelopard
|
|
2147
2210
|
e
|
2148
2211
|
end
|
2149
2212
|
end
|
2150
|
-
|
2151
2213
|
end
|
2152
2214
|
# End of Kamelopard module
|
data/lib/kamelopard/functions.rb
CHANGED
@@ -4,31 +4,63 @@ def fly_to(p, d = 0, r = 100, m = nil)
|
|
4
4
|
Kamelopard::FlyTo.new p, :range => r, :duration => d, :mode => m
|
5
5
|
end
|
6
6
|
|
7
|
+
def get_document()
|
8
|
+
Kamelopard::Document.instance
|
9
|
+
end
|
10
|
+
|
7
11
|
def set_flyto_mode_to(a)
|
8
12
|
Kamelopard::Document.instance.flyto_mode = a
|
9
13
|
end
|
10
14
|
|
11
|
-
def
|
12
|
-
au = Kamelopard::AnimatedUpdate.new
|
15
|
+
def toggle_balloon_for(p, v, options = {})
|
16
|
+
au = Kamelopard::AnimatedUpdate.new [], options
|
17
|
+
if ! p.kind_of? Kamelopard::Placemark and ! p.kind_of? Kamelopard::ScreenOverlay then
|
18
|
+
raise "Can't show balloons for things that aren't Placemarks or ScreenOverlays"
|
19
|
+
end
|
20
|
+
a = XML::Node.new 'Change'
|
21
|
+
# XXX This can probably be more robust, based on just the class's name
|
22
|
+
if p.kind_of? Kamelopard::Placemark then
|
23
|
+
b = XML::Node.new 'Placemark'
|
24
|
+
else
|
25
|
+
b = XML::Node.new 'ScreenOverlay'
|
26
|
+
end
|
27
|
+
b.attributes['targetId'] = p.kml_id
|
28
|
+
c = XML::Node.new 'gx:balloonVisibility'
|
29
|
+
c << XML::Node.new_text(v.to_s)
|
30
|
+
b << c
|
31
|
+
a << b
|
32
|
+
au << a
|
33
|
+
end
|
34
|
+
|
35
|
+
def hide_balloon_for(p, options = {})
|
36
|
+
toggle_balloon_for(p, 0, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def show_balloon_for(p, options = {})
|
40
|
+
toggle_balloon_for(p, 1, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def fade_balloon_for(p, v, options = {})
|
44
|
+
au = Kamelopard::AnimatedUpdate.new [], options
|
13
45
|
if ! p.is_a? Kamelopard::Placemark then
|
14
|
-
raise "Can't show
|
46
|
+
raise "Can't show balloons for things that aren't placemarks"
|
15
47
|
end
|
16
48
|
a = XML::Node.new 'Change'
|
17
49
|
b = XML::Node.new 'Placemark'
|
18
50
|
b.attributes['targetId'] = p.kml_id
|
19
|
-
c = XML::Node.new '
|
51
|
+
c = XML::Node.new 'color'
|
20
52
|
c << XML::Node.new_text(v.to_s)
|
21
53
|
b << c
|
22
54
|
a << b
|
23
55
|
au << a
|
24
56
|
end
|
25
57
|
|
26
|
-
def
|
27
|
-
|
58
|
+
def fade_out_balloon_for(p, options = {})
|
59
|
+
fade_balloon_for(p, '00ffffff', options)
|
28
60
|
end
|
29
61
|
|
30
|
-
def
|
31
|
-
|
62
|
+
def fade_in_balloon_for(p, options = {})
|
63
|
+
fade_balloon_for(p, 'ffffffff', options)
|
32
64
|
end
|
33
65
|
|
34
66
|
def point(lo, la, alt=0, mode=nil, extrude = false)
|
@@ -36,6 +68,10 @@ def point(lo, la, alt=0, mode=nil, extrude = false)
|
|
36
68
|
Kamelopard::Point.new(lo, la, alt, :altitudeMode => m, :extrude => extrude)
|
37
69
|
end
|
38
70
|
|
71
|
+
def placemark(name = nil, options = {})
|
72
|
+
Kamelopard::Placemark.new name, options
|
73
|
+
end
|
74
|
+
|
39
75
|
# Returns the KML that makes up the current Kamelopard::Document, as a string.
|
40
76
|
def get_kml
|
41
77
|
Kamelopard::Document.instance.get_kml_document
|
@@ -49,11 +85,19 @@ def pause(p)
|
|
49
85
|
Kamelopard::Wait.new p
|
50
86
|
end
|
51
87
|
|
88
|
+
def get_tour()
|
89
|
+
Kamelopard::Document.instance.tour
|
90
|
+
end
|
91
|
+
|
52
92
|
def name_tour(a)
|
53
93
|
Kamelopard::Document.instance.tour.name = a
|
54
94
|
end
|
55
95
|
|
56
|
-
def
|
96
|
+
def get_folder()
|
97
|
+
Kamelopard::Document.instance.folders.last
|
98
|
+
end
|
99
|
+
|
100
|
+
def folder(name)
|
57
101
|
Kamelopard::Folder.new(name)
|
58
102
|
end
|
59
103
|
|
@@ -62,6 +106,11 @@ def name_folder(a)
|
|
62
106
|
return Kamelopard::Document.instance.folder
|
63
107
|
end
|
64
108
|
|
109
|
+
def name_document(a)
|
110
|
+
Kamelopard::Document.instance.name = a
|
111
|
+
return Kamelopard::Document.instance
|
112
|
+
end
|
113
|
+
|
65
114
|
def zoom_out(dist = 1000, dur = 0, mode = nil)
|
66
115
|
l = Kamelopard::Document.instance.tour.last_abs_view
|
67
116
|
raise "No current position to zoom out from\n" if l.nil?
|
@@ -135,7 +184,8 @@ def set_prefix_to(a)
|
|
135
184
|
end
|
136
185
|
|
137
186
|
def write_kml_to(file = 'doc.kml')
|
138
|
-
File.open(file, 'w') do |f| f.write get_kml.to_s
|
187
|
+
File.open(file, 'w') do |f| f.write get_kml.to_s end
|
188
|
+
#File.open(file, 'w') do |f| f.write get_kml.to_s.gsub(/balloonVis/, 'gx:balloonVis') end
|
139
189
|
end
|
140
190
|
|
141
191
|
def fade_overlay(ov, show, options = {})
|
@@ -150,20 +200,6 @@ def fade_overlay(ov, show, options = {})
|
|
150
200
|
k
|
151
201
|
end
|
152
202
|
|
153
|
-
def mod_balloon_for(a, val)
|
154
|
-
c = a.change('gx:balloonVisibility', val).to_s
|
155
|
-
STDERR.puts c
|
156
|
-
Kamelopard::AnimatedUpdate.new c
|
157
|
-
end
|
158
|
-
|
159
|
-
def show_balloon_for(a)
|
160
|
-
Kamelopard::AnimatedUpdate.new %{<Change><Placemark targetId="#{a.kml_id}"><balloonVisibility>1</balloonVisibility></Placemark></Change>}
|
161
|
-
end
|
162
|
-
|
163
|
-
def hide_balloon_for(a)
|
164
|
-
Kamelopard::AnimatedUpdate.new %{<Change><Placemark targetId="#{a.kml_id}"><balloonVisibility>0</balloonVisibility></Placemark></Change>}
|
165
|
-
end
|
166
|
-
|
167
203
|
module TelemetryProcessor
|
168
204
|
Pi = 3.1415926535
|
169
205
|
|
@@ -281,3 +317,104 @@ def tour_from_points(points, options = {})
|
|
281
317
|
TelemetryProcessor::add_flyto points[i,3]
|
282
318
|
end
|
283
319
|
end
|
320
|
+
|
321
|
+
def make_view_from(options = {})
|
322
|
+
o = {}
|
323
|
+
o.merge! options
|
324
|
+
options.each do |k, v|
|
325
|
+
o[k.to_sym] = v unless k.kind_of? Symbol
|
326
|
+
end
|
327
|
+
|
328
|
+
# Set defaults
|
329
|
+
[
|
330
|
+
[ :altitude, 0 ],
|
331
|
+
[ :altitudeMode, :relativeToGround ],
|
332
|
+
[ :latitude, 0 ],
|
333
|
+
[ :longitude, 0 ],
|
334
|
+
[ :tilt, 0 ],
|
335
|
+
[ :heading, 0 ],
|
336
|
+
].each do |a|
|
337
|
+
o[a[0]] = a[1] unless o.has_key? a[0]
|
338
|
+
end
|
339
|
+
|
340
|
+
p = point o[:longitude], o[:latitude], o[:altitude], o[:altitudeMode]
|
341
|
+
|
342
|
+
if o.has_key? :roll then
|
343
|
+
view = Kamelopard::Camera.new p
|
344
|
+
else
|
345
|
+
view = Kamelopard::LookAt.new p
|
346
|
+
end
|
347
|
+
|
348
|
+
[ :altitudeMode, :tilt, :heading, :timestamp, :timespan, :timestamp, :range, :roll, :viewerOptions ].each do |a|
|
349
|
+
view.method("#{a.to_s}=").call(o[a]) if o.has_key? a
|
350
|
+
end
|
351
|
+
|
352
|
+
view
|
353
|
+
end
|
354
|
+
|
355
|
+
def screenoverlay(options = {})
|
356
|
+
Kamelopard::ScreenOverlay.new options
|
357
|
+
end
|
358
|
+
|
359
|
+
def xy(x = 0.5, y = 0.5, xt = :fraction, yt = :fraction)
|
360
|
+
Kamelopard::XY.new x, y, xt, yt
|
361
|
+
end
|
362
|
+
|
363
|
+
def iconstyle(href = nil, options = {})
|
364
|
+
Kamelopard::IconStyle.new href, options
|
365
|
+
end
|
366
|
+
|
367
|
+
def labelstyle(scale = 1, options = {})
|
368
|
+
Kamelopard::LabelStyle.new scale, options
|
369
|
+
end
|
370
|
+
|
371
|
+
def style(options = {})
|
372
|
+
Kamelopard::Style.new options
|
373
|
+
end
|
374
|
+
|
375
|
+
def look_at(point = nil, options = {})
|
376
|
+
Kamelopard::LookAt.new point, options
|
377
|
+
end
|
378
|
+
|
379
|
+
def camera(point = nil, options = {})
|
380
|
+
Kamelopard::Camera.new point, options
|
381
|
+
end
|
382
|
+
|
383
|
+
def fly_to(view = nil, options = {})
|
384
|
+
Kamelopard::FlyTo.new view, options
|
385
|
+
end
|
386
|
+
|
387
|
+
# k = an XML::Document containing KML
|
388
|
+
# Pulls the Placemarks from the KML document and flys to each one in turn
|
389
|
+
def each_placemark(d)
|
390
|
+
i = 0
|
391
|
+
d.find('//kml:Placemark').each do |p|
|
392
|
+
all_values = {}
|
393
|
+
|
394
|
+
# These fields are part of the abstractview
|
395
|
+
view_fields = %w{ latitude longitude heading range tilt roll altitude altitudeMode gx:altitudeMode }
|
396
|
+
# These are other field I'm interested in
|
397
|
+
other_fields = %w{ description name }
|
398
|
+
all_fields = view_fields.clone
|
399
|
+
all_fields.concat(other_fields.clone)
|
400
|
+
all_fields.each do |k|
|
401
|
+
if k == 'gx:altitudeMode' then
|
402
|
+
ix = k
|
403
|
+
next unless p.find_first('kml:altitudeMode').nil?
|
404
|
+
else
|
405
|
+
ix = "kml:#{k}"
|
406
|
+
end
|
407
|
+
r = k == "gx:altitudeMode" ? :altitudeMode : k.to_sym
|
408
|
+
tmp = p.find_first("descendant::#{ix}")
|
409
|
+
next if tmp.nil?
|
410
|
+
all_values[k == "gx:altitudeMode" ? :altitudeMode : k.to_sym ] = tmp.content
|
411
|
+
end
|
412
|
+
view_values = {}
|
413
|
+
view_fields.each do |v| view_values[v] = all_values[v].clone if all_values.has_key? v end
|
414
|
+
yield make_view_from(view_values), all_values
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
def make_tour_index(erb = nil, options = {})
|
419
|
+
get_document.make_tour_index(erb, options)
|
420
|
+
end
|
data/lib/kamelopard/pointlist.rb
CHANGED
@@ -2,72 +2,54 @@
|
|
2
2
|
require 'matrix'
|
3
3
|
#require 'kamelopard_classes'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
# XXX Right now I'm changing this to handle one-dimensional lists of numbers,
|
6
|
+
# that can be added together. We'll probably want a way to add points, or other
|
7
|
+
# numeric sets, to a set of pointlists easily. So for instance we can have
|
8
|
+
# lists for altitude, longitude, and latitude, and add a single point to them
|
9
|
+
# in one easy command.
|
10
|
+
|
11
|
+
module Kamelopard
|
12
|
+
class NumberList
|
13
|
+
# Contains a list of numbers
|
14
|
+
|
15
|
+
def initialize(init = [])
|
16
|
+
raise "Constructor argument needs to be an array" unless init.kind_of? Array
|
17
|
+
@points = init
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
def size
|
21
|
+
return @points.size
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
# Append points to our list
|
22
|
-
if a.kind_of? Kamelopard::Point then
|
23
|
-
if self.dim == 3 then
|
24
|
-
@points << [a.longitude, a.latitude, a.altitude]
|
25
|
-
else
|
26
|
-
@points << [a.longitude, a.latitude]
|
27
|
-
end
|
28
|
-
elsif a.respond_to? 'dim' and @dim != a.dim then
|
29
|
-
raise "Argument's dimension #{a.dim} must agree with our dimension #{@dim} to append to an NDPointList"
|
30
|
-
else
|
24
|
+
def <<(a)
|
31
25
|
@points << a
|
32
26
|
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def last
|
36
|
-
@points.last
|
37
|
-
end
|
38
27
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def x
|
44
|
-
@points.collect do |a| a[0] end
|
45
|
-
end
|
28
|
+
def last
|
29
|
+
@points.last
|
30
|
+
end
|
46
31
|
|
47
|
-
|
48
|
-
|
49
|
-
@points.collect do |a| a[1] end
|
50
|
-
else
|
51
|
-
raise "NDPointList of size #{@dim} has no Y element"
|
32
|
+
def [](i)
|
33
|
+
@points[i]
|
52
34
|
end
|
53
|
-
end
|
54
35
|
|
55
|
-
|
56
|
-
|
57
|
-
@points.collect do |a| a[2] end
|
58
|
-
else
|
59
|
-
raise "NDPointList of size #{@dim} has no Z element"
|
36
|
+
def each(&blk)
|
37
|
+
@points.each(&blk)
|
60
38
|
end
|
61
39
|
end
|
62
|
-
|
63
|
-
def
|
64
|
-
|
40
|
+
|
41
|
+
def Kamelopard.lists_at(lists, i)
|
42
|
+
# The modulus ensures lists will repeat if they're not the same size
|
43
|
+
lists.collect { |l| l[i % l.size] }
|
65
44
|
end
|
66
45
|
|
67
|
-
def interpolate(resolution = [10])
|
46
|
+
def Kamelopard.interpolate(lists = [], resolution = [10])
|
68
47
|
# Ruby implementation of Catmull-Rom splines (http://www.cubic.org/docs/hermite.htm)
|
69
48
|
# Return NDPointList interpolating a path along all points in this list
|
70
49
|
|
50
|
+
size = lists.collect { |l| l.size }.max
|
51
|
+
STDERR.puts size
|
52
|
+
|
71
53
|
h = Matrix[
|
72
54
|
[ 2, -2, 1, 1 ],
|
73
55
|
[-3, 3, -2, -1 ],
|
@@ -75,19 +57,20 @@ class NDPointList
|
|
75
57
|
[ 1, 0, 0, 0 ],
|
76
58
|
]
|
77
59
|
|
78
|
-
|
60
|
+
# XXX This needs to be fixed
|
61
|
+
result = []
|
79
62
|
|
80
63
|
idx = 0
|
81
|
-
resolution = [resolution] if ! resolution.respond_to? []
|
64
|
+
resolution = [resolution] if ! resolution.respond_to? :[]
|
82
65
|
|
83
66
|
# Calculate spline between every two points
|
84
|
-
(0..(
|
85
|
-
p1 =
|
86
|
-
p2 =
|
67
|
+
(0..(size-2)).each do |i|
|
68
|
+
p1 = lists_at(lists, i)
|
69
|
+
p2 = lists_at(lists, i+1)
|
87
70
|
|
88
71
|
# Get surrounding points for calculating tangents
|
89
|
-
if i <= 0 then pt1 = p1 else pt1 =
|
90
|
-
if i
|
72
|
+
if i <= 0 then pt1 = p1 else pt1 = lists_at(lists, i-1) end
|
73
|
+
if i >= size - 2 then pt2 = p2 else pt2 = lists_at(lists, i+2) end
|
91
74
|
|
92
75
|
# Build tangent points into matrices to calculate tangents.
|
93
76
|
t1 = 0.5 * ( Matrix[p2] - Matrix[pt1] )
|
@@ -97,7 +80,8 @@ class NDPointList
|
|
97
80
|
c = Matrix[p1, p2, t1.row(0), t2.row(0)]
|
98
81
|
|
99
82
|
# Make a set of points
|
100
|
-
point_count = (resolution[idx] * 1.0 /
|
83
|
+
point_count = (resolution[idx] * 1.0 / size).to_i
|
84
|
+
STDERR.puts point_count
|
101
85
|
(0..point_count).each do |t|
|
102
86
|
r = t/10.0
|
103
87
|
s = Matrix[[r**3, r**2, r, 1]]
|
@@ -112,20 +96,11 @@ class NDPointList
|
|
112
96
|
end
|
113
97
|
end
|
114
98
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
super 2
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
class ThreeDPointList < NDPointList
|
128
|
-
def initialize
|
129
|
-
super 3
|
130
|
-
end
|
131
|
-
end
|
99
|
+
#a = Kamelopard::NumberList.new [1, 2, 3]
|
100
|
+
#b = Kamelopard::NumberList.new [5, 6, 10]
|
101
|
+
#
|
102
|
+
#i = 0
|
103
|
+
#Kamelopard.interpolate([a, b], [100]).each do |f|
|
104
|
+
# i += 1
|
105
|
+
# puts "#{i}\t#{f.inspect}"
|
106
|
+
#end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kamelopard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joshua Tolley
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2012-
|
19
|
+
date: 2012-07-12 00:00:00 Z
|
20
20
|
dependencies: []
|
21
21
|
|
22
22
|
description: Various classes and functions used to ease development of KML files, in particular for development of Google Earth tours
|